<?php
/**
 * Caterpoint Integration Module for Yii2
 *
 * @category    PortalPeople
 * @package     Caterpoint
 * @author      Portal People Development Team
 * @copyright   Copyright (c) 2026 Portal People (https://portalpeople.co.uk)
 */

namespace PortalPeople\caterpoint;

use Yii;
use yii\base\BootstrapInterface;
use yii\base\InvalidConfigException;
use yii\base\Module as BaseModule;
use yii\console\Application as ConsoleApplication;
use backend\components\Security;
use PortalPeople\caterpoint\components\CaterpointClient;
use PortalPeople\caterpoint\services\OrderImportService;
use PortalPeople\caterpoint\services\CaterpointCursorStore;
use yii\base\Event;
/**
 * Caterpoint Integration Module
 * 
 * This module provides integration with Caterpoint API for order synchronization
 */
class Module extends BaseModule implements BootstrapInterface
{
    /**
     * @var string default route for module entry
     */
    public $defaultRoute = 'config/index';

    /**
     * @var string the namespace that controller classes are in
     */
    public $controllerNamespace = 'PortalPeople\\caterpoint\\controllers';

    /**
     * @var string Caterpoint API base URL
     */
    public $apiEndpoint = '';

    /**
     * @var string Caterpoint API token
     */
    public $apiToken = '';

    /**
     * @var int Request timeout in seconds
     */
    public $requestTimeout = 30;

    /**
     * @var int Poll limit for orders per request
     */
    public $pollLimit = 100;

    /**
     * @var bool Mark Caterpoint orders as exported after successful local import
     */
    public $autoMarkExported = false;

    /**
     * @var string Order number prefix for generated order references
     */
    public $orderNumberPrefix = 'CP-';

    /**
     * @var string Cursor storage key for order import tracking
     */
    public $orderImportCursorKey = 'caterpoint.order-import.cursor';

    /**
     * @var string Runtime path for cursor file storage
     */
    public $orderImportCursorFile = '@runtime/caterpoint/order-import.cursor';

    /**
     * @var array Order status mapping from Caterpoint to local system
     */
    public $statusMap = [
        'pending' => 'Pending',
        'processing' => 'Processing',
        'confirmed' => 'Confirmed',
        'dispatched' => 'Dispatched',
        'delivered' => 'Delivered',
        'cancelled' => 'Cancelled',
    ];

    /**
     * @var string Fully-qualified class name for the local order model.
     * Leave empty to use the default (frontend\\models\\erpModels\\SalesOrders).
     */
    public $orderModelClass = '';

    /**
     * @var string Fully-qualified class name for the local order-line model.
     * Leave empty to omit per-line model configuration.
     */
    public $orderLineModelClass = '';

    /**
     * @var bool Enable debug logging
     */
    public $debug = false;

    /**
     * Bootstrap method to initialize the module
     * 
     * @param \yii\base\Application $app the application currently running
     */
    public function bootstrap($app)
    {
        $this->id = 'caterpoint';

        if (!isset($app->getModules()[$this->id])) {
            $app->setModule($this->id, $this);
        }

        if (!($app instanceof ConsoleApplication) && isset($app->urlManager)) {
            $app->urlManager->addRules([
                // API routes - raw JSON/XML responses
                "api/{$this->id}/<controller:[\\w\\-]+>/<action:[\\w\\-]+>" => "{$this->id}/api/<controller>/<action>",
                
                // NGauge routes - friendly HTML responses
                "{$this->id}/<action:[\\w\\-]+>" => "{$this->id}/config/<action>",
                "{$this->id}/<controller:[\\w\\-]+>/<action:[\\w\\-]+>" => "{$this->id}/<controller>/<action>",
            ], false);
        }
        Event::on(\backend\models\ProductsData::class, 'products-set-data-types', function($event){
            $event->buttons['caterpoint'] = 'caterpoint';
            $dir = Yii::getAlias('@frontend/models/Products');
            foreach (glob($dir . '/*.php') as $file) {
                $prefix = strtolower(basename($file, '.php'));
                $event->buttons[$prefix] = $prefix;
            }
            Yii::warning($event->buttons, 'Caterpoint Integration - Set Data Types');
        });
        $dir = Yii::getAlias('@frontend/models/Products');
        foreach (glob($dir . '/*.php') as $file) {
            $shortName = basename($file, '.php');
            Yii::$app->on('products-after-DataLoad-' . strtolower($shortName), function($event) use ($shortName) {
                $event->result = 'frontend\\models\\Products\\' . $shortName;
            });
        }
        Yii::$app->on('products-after-DataLoad-caterpoint', function($event){
            $event->result = \PortalPeople\caterpoint\models\products\Caterpoint::class;
            }
        );
        
        Yii::$app->on('setImportFields', function($event){
            $custom = [];
            foreach (\PortalPeople\caterpoint\models\products\Caterpoint::localattributes() as $field => $data) {
                $custom[$this->id . '__' . $field] = $data;
            }
          
            $event->result = $custom;
        });
       
    }

    /**
     * Initialize the module
     */
    public function init()
    {
        parent::init();

        $this->loadConfigFromParams();

        if (Yii::$app instanceof ConsoleApplication) {
            $this->controllerNamespace = 'PortalPeople\\caterpoint\\commands';
        }

        $this->registerDataHooks();
    }

    /**
     * Check if the module is properly configured
     * 
     * @return bool
     */
    public function isConfigured(): bool
    {
        return trim((string) $this->apiEndpoint) !== '' && trim((string) $this->apiToken) !== '';
    }

    /**
     * Create a new Caterpoint API client
     * 
     * @return CaterpointClient
     * @throws InvalidConfigException if the module is not configured
     */
    public function createClient(): CaterpointClient
    {
        if (!$this->isConfigured()) {
            throw new InvalidConfigException('Caterpoint API endpoint and token must be configured.');
        }

        return new CaterpointClient([
            'apiEndpoint' => $this->apiEndpoint,
            'apiToken' => (string) $this->apiToken,
            'timeout' => (int) $this->requestTimeout,
        ]);
    }

    /**
     * Create an order import service
     * 
     * @return OrderImportService
     */
    public function createOrderImportService(): OrderImportService
    {
        return new OrderImportService([
            'client' => $this->createClient(),
            'cursorStore' => new CaterpointCursorStore([
                'cacheKey' => $this->orderImportCursorKey,
                'filePath' => Yii::getAlias($this->orderImportCursorFile),
            ]),
            'module'                 => $this,
            'defaultLimit'           => (int) $this->pollLimit,
            'markExportedAfterImport'=> (bool) $this->autoMarkExported,
            'orderModelClass'        => $this->orderModelClass,
            'orderLineModelClass'    => $this->orderLineModelClass,
        ]);
    }

    /**
     * Load configuration from Yii params
     */
    private function loadConfigFromParams(): void
    {
        $params = Yii::$app->params;

        $config = $params['plugins']['caterpoint'] ?? $params['caterpoint'] ?? null;
        if (!is_array($config)) {
            return;
        }

        foreach (['apiEndpoint', 'requestTimeout', 'pollLimit', 'orderNumberPrefix', 'autoMarkExported', 'debug', 'orderModelClass', 'orderLineModelClass'] as $key) {
            if (array_key_exists($key, $config)) {
                $this->$key = $config[$key];
            }
        }

        if (array_key_exists('apiToken', $config)) {
            $apiToken = (string) $config['apiToken'];
            if ($apiToken !== '' && class_exists(Security::class)) {
                $this->apiToken = Security::decryptSensitiveData($apiToken);
            } else {
                $this->apiToken = $apiToken;
            }
        }

        if (array_key_exists('statusMap', $config)) {
            $statusMap = $config['statusMap'];
            if (is_array($statusMap)) {
                $this->statusMap = $statusMap;
            } elseif (is_string($statusMap) && $statusMap !== '') {
                $decoded = json_decode($statusMap, true);
                if (is_array($decoded)) {
                    $this->statusMap = $decoded;
                }
            }
        }
    }

    /**
     * Register data hooks for order events
     */
    private function registerDataHooks(): void
    {
        // Register any event listeners or hooks here
    }

    /**
     * Map Caterpoint order status to local system status
     * 
     * @param string $status Caterpoint order status
     * @return string Local system status
     */
    public function mapStatus(string $status): string
    {
        return $this->statusMap[strtolower($status)] ?? $status;
    }

    /**
     * Generate a local order number from Caterpoint order reference
     * 
     * @param string $caterpointOrderRef Caterpoint order reference
     * @return string Generated order number
     */
    public function makeOrderNumber(string $caterpointOrderRef): string
    {
        return $this->orderNumberPrefix . $caterpointOrderRef;
    }
}
