<?php

/**
 * Configuration Form Model – VirtualStock Module
 *
 * @category    PortalPeople
 * @package     VirtualStock
 * @author      Portal People Development Team
 * @copyright   Copyright (c) 2026 Portal People (https://portalpeople.co.uk)
 */

namespace PortalPeople\virtualstock\models;

use Yii;
use yii\base\Model;
use backend\components\Security;
use PortalPeople\virtualstock\constants\ApiEndpoints;

/**
 * ConfigForm
 *
 * Stores and validates VirtualStock connection settings, which are persisted to
 * `backend/config/params-local.php` under the key `plugins.virtualstock`.
 */
class ConfigForm extends Model
{
    /** @var bool Enable the integration. */
    public bool $enabled = false;

    /**
     * @var string Environment selection.
     * One of 'sandbox' or 'production'. Setting this auto-populates apiEndpoint
     * unless a custom URL is provided.
     */
    public string $environment = 'sandbox';

    /** @var string VirtualStock REST API base URL (overrides environment default when set). */
    public string $apiEndpoint = '';

    /** @var string VirtualStock API key. */
    public string $apiKey = '';

    /** @var string VirtualStock API secret. */
    public string $apiSecret = '';

    /** @var int HTTP request timeout in seconds. */
    public int $requestTimeout = 30;

    /** @var int Maximum orders to poll per import run. */
    public int $pollLimit = 100;

    /** @var string Prefix prepended to VirtualStock order numbers in this system. */
    public string $orderNumberPrefix = 'VS-';

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

    /** @var bool Route async jobs through the queue instead of processing inline. */
    public bool $useQueue = false;

    /** @var string Yii application component ID for the queue. */
    public string $queueComponent = 'virtualstock-queue';

    // -------------------------------------------------------------------------

    /** @inheritdoc */
    public function rules(): array
    {
        return [
            [['environment'], 'in', 'range' => ['sandbox', 'production']],
            [['apiEndpoint'], 'url', 'defaultScheme' => 'https', 'skipOnEmpty' => true],
            [['apiKey', 'apiSecret'], 'required', 'when' => function (self $model) {
                return $model->enabled;
            }, 'whenClient' => "function (attribute, value) {
                return $('#configform-enabled').is(':checked');
            }"],
            [['apiKey', 'apiSecret', 'apiEndpoint', 'orderNumberPrefix'], 'string'],
            [['requestTimeout'], 'integer', 'min' => 5, 'max' => 120],
            [['pollLimit'], 'integer', 'min' => 1, 'max' => 500],
            [['enabled', 'debug', 'useQueue'], 'boolean'],
            [['environment'], 'string'],
            [['queueComponent'], 'string', 'max' => 64],
            [['queueComponent'], 'match', 'pattern' => '/^[a-zA-Z0-9_-]+$/',
                'message' => 'Component ID may only contain letters, numbers, hyphens and underscores.'],
        ];
    }

    /** @inheritdoc */
    public function attributeLabels(): array
    {
        return [
            'enabled'           => 'Enable Integration',
            'environment'       => 'Environment',
            'apiEndpoint'       => 'API Endpoint URL',
            'apiKey'            => 'API Key',
            'apiSecret'         => 'API Secret',
            'requestTimeout'    => 'Request Timeout (seconds)',
            'pollLimit'         => 'Order Poll Limit',
            'orderNumberPrefix' => 'Order Number Prefix',
            'debug'             => 'Enable Debug Logging',
            'useQueue'          => 'Enable Queue Processing',
            'queueComponent'    => 'Queue Component ID',
        ];
    }

    /** @inheritdoc */
    public function attributeHints(): array
    {
        return [
            'environment'       => 'Sandbox uses the VirtualStock test environment. Switch to Production when ready to go live.',
            'apiEndpoint'       => 'Leave blank to use the default URL for the selected environment.',
            'apiKey'            => 'API key provided by VirtualStock.',
            'apiSecret'         => 'API secret provided by VirtualStock.',
            'requestTimeout'    => 'Seconds to wait for an API response before timing out (5–120).',
            'pollLimit'         => 'Maximum number of orders fetched per import run (1–500).',
            'orderNumberPrefix' => 'Short prefix added to VirtualStock order numbers, e.g. "VS-12345".',
            'useQueue'          => 'When enabled, order import and webhook jobs are dispatched to the queue instead of running inline.',
            'queueComponent'    => 'Yii application component ID of the ngauge-queue instance to use (e.g. virtualstock-queue).',
        ];
    }

    // -------------------------------------------------------------------------

    /**
     * Populate model from current params-local.php values.
     */
    public function loadFromParams(): void
    {
        $config = Yii::$app->params['plugins']['virtualstock'] ?? [];

        $this->enabled           = (bool)   ($config['enabled']           ?? false);
        $this->environment       = (string) ($config['environment']       ?? 'sandbox');
        $this->apiEndpoint       = (string) ($config['apiEndpoint']       ?? '');
        $this->apiKey            = Security::decryptSensitiveData($config['apiKey']    ?? '');
        $this->apiSecret         = Security::decryptSensitiveData($config['apiSecret'] ?? '');
        $this->requestTimeout    = (int)    ($config['requestTimeout']    ?? 30);
        $this->pollLimit         = (int)    ($config['pollLimit']         ?? 100);
        $this->orderNumberPrefix = (string) ($config['orderNumberPrefix'] ?? 'VS-');
        $this->debug             = (bool)   ($config['debug']             ?? false);
        $this->useQueue          = (bool)   ($config['useQueue']          ?? false);
        $this->queueComponent    = (string) ($config['queueComponent']    ?? 'virtualstock-queue');
    }

    /**
     * Persist model data to params-local.php.
     *
     * @return bool
     */
    public function saveToParams(): bool
    {
        $paramsFile = Yii::getAlias('@backend/config/params-local.php');

        if (!file_exists($paramsFile)) {
            Yii::error('params-local.php not found: ' . $paramsFile, 'virtualstock');
            return false;
        }

        $params = require $paramsFile;

        if (!isset($params['plugins'])) {
            $params['plugins'] = [];
        }

        // Resolve the effective endpoint — use explicit override or environment default.
        $effectiveEndpoint = trim($this->apiEndpoint) !== ''
            ? $this->apiEndpoint
            : ($this->environment === 'production' ? ApiEndpoints::PRODUCTION : ApiEndpoints::SANDBOX);

        $params['plugins']['virtualstock'] = [
            'enabled'           => (bool)   $this->enabled,
            'environment'       => (string) $this->environment,
            'apiEndpoint'       => $effectiveEndpoint,
            'apiKey'            => Security::encryptSensitiveData($this->apiKey),
            'apiSecret'         => Security::encryptSensitiveData($this->apiSecret),
            'requestTimeout'    => (int)    $this->requestTimeout,
            'pollLimit'         => (int)    $this->pollLimit,
            'orderNumberPrefix' => (string) $this->orderNumberPrefix,
            'debug'             => (bool)   $this->debug,
            'useQueue'          => (bool)   $this->useQueue,
            'queueComponent'    => (string) $this->queueComponent,
        ];

        $export = "<?php\nreturn " . var_export($params, true) . ";\n";

        if (file_put_contents($paramsFile, $export) === false) {
            Yii::error('Failed to write params-local.php: ' . $paramsFile, 'virtualstock');
            return false;
        }

        // Invalidate opcache so the updated file is picked up immediately.
        if (function_exists('opcache_invalidate')) {
            opcache_invalidate($paramsFile, true);
        }

        return true;
    }

    /**
     * Test the API connection using the current form values (not saved params).
     *
     * Attempts a minimal authenticated request and returns a result array.
     *
     * @return array{success: bool, message: string}
     */
    public function testConnection(): array
    {
        try {
            $endpoint = trim($this->apiEndpoint) !== ''
                ? $this->apiEndpoint
                : ($this->environment === 'production' ? ApiEndpoints::PRODUCTION : ApiEndpoints::SANDBOX);

            $client = new \PortalPeople\virtualstock\components\VirtualStockClient([
                'apiEndpoint' => $endpoint,
                'apiKey'      => $this->apiKey,
                'apiSecret'   => $this->apiSecret,
                'timeout'     => $this->requestTimeout,
            ]);

            // Fetch at most 1 order to verify authentication and connectivity.
            $client->getOrdersUpdatedSince(null, 1);

            return [
                'success' => true,
                'message' => 'Connection successful. VirtualStock API is reachable.',
            ];
        } catch (\PortalPeople\virtualstock\exceptions\AuthenticationException $e) {
            return [
                'success' => false,
                'message' => 'Authentication failed. Please check your API key and secret.',
            ];
        } catch (\PortalPeople\virtualstock\exceptions\ApiException $e) {
            return [
                'success' => false,
                'message' => 'API error (' . $e->getStatusCode() . '): ' . $e->getMessage(),
            ];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => 'Connection failed: ' . $e->getMessage(),
            ];
        }
    }
}
