<?php

declare(strict_types=1);

namespace PortalPeople\datadash;

use PortalPeople\datadash\services\DataService;
use PortalPeople\datadash\services\DataServicesService;
use yii\base\BootstrapInterface;
use yii\base\Module as BaseModule;
use Yii;

/**
 * ngauge-datadash module
 *
 * Datafeeds dashboard — provides order download, CSV export, and Tour Operator
 * data feed endpoints (SLT, SOH, SOD, STA, SLA).
 */
class Module extends BaseModule implements BootstrapInterface
{
    public string $moduleId = 'ngauge-datadash';
    public bool   $enabled  = true;

    /** @var DataService|null */
    private ?DataService $dataService = null;

    /** @var DataServicesService|null */
    private ?DataServicesService $dataServicesService = null;

    public $controllerNamespace = 'PortalPeople\\datadash\\controllers';

    public function init(): void
    {
        parent::init();

        $config = Yii::$app->params['plugins'][$this->moduleId] ?? [];

        if (isset($config['enabled'])) {
            $this->enabled = (bool)$config['enabled'];
        }
    }

    public function bootstrap($app): void
    {
        $app->setModule($this->moduleId, $this);

        // Bootstrap the 'datadash' DB component from saved configuration so
        // every application that loads this module gets the connection automatically.
        $this->bootstrapDbComponent($app);

        if ($app instanceof \yii\web\Application) {
            $app->getUrlManager()->addRules([
                // Config UI — CRUD for named connections
                'datadash/config/index'                       => 'ngauge-datadash/config/index',
                'datadash/config/create'                      => 'ngauge-datadash/config/create',
                'datadash/config/update'                      => 'ngauge-datadash/config/update',
                'POST datadash/config/delete'                 => 'ngauge-datadash/config/delete',
                'POST datadash/config/test-connection'        => 'ngauge-datadash/config/test-connection',
                'POST datadash/config/list-tables'            => 'ngauge-datadash/config/list-tables',
                'POST datadash/config/validate'               => 'ngauge-datadash/config/validate',
                'datadash/config/generate'                    => 'ngauge-datadash/config/generate',
                'POST datadash/config/do-generate'            => 'ngauge-datadash/config/do-generate',
                // Data-feed endpoints
                'POST df/data/upload'            => 'ngauge-datadash/api/data/upload',
                'GET df/data/downloadorders'     => 'ngauge-datadash/api/data/downloadorders',
                'GET df/data/downloadpaidorders' => 'ngauge-datadash/api/data/downloadpaidorders',
                'GET df/data/downloadcsv'        => 'ngauge-datadash/api/data/downloadcsv',
                'GET df/data/downloadpaidcsv'    => 'ngauge-datadash/api/data/downloadpaidcsv',
                'GET df/data/downloadcsvgroup'   => 'ngauge-datadash/api/data/downloadcsvgroup',
                'POST df/data/downloaded'        => 'ngauge-datadash/api/data/downloaded',
                'GET df/data-services/slt'       => 'ngauge-datadash/api/data-services/slt',
                'GET df/data-services/soh'       => 'ngauge-datadash/api/data-services/soh',
                'GET df/data-services/sod'       => 'ngauge-datadash/api/data-services/sod',
                'GET df/data-services/sta'       => 'ngauge-datadash/api/data-services/sta',
                'GET df/data-services/sla'       => 'ngauge-datadash/api/data-services/sla',
            ], false);
        }
    }

    /**
     * Register Yii DB components for all named datadash connections.
     *
     * Each connection stored under params['plugins']['ngauge-datadash']['connections'][$name]
     * is registered as the component 'datadash_{name}', skipping any that are already set.
     */
    private function bootstrapDbComponent(\yii\base\Application $app): void
    {
        if (!$this->enabled) {
            return;
        }

        $moduleConfig = Yii::$app->params['plugins'][$this->moduleId] ?? [];
        $connections  = $moduleConfig['connections'] ?? [];

        foreach ($connections as $name => $config) {
            $componentId = 'datadash_' . $name;

            if ($app->has($componentId, true)) {
                continue; // already wired
            }

            if (empty($config['host']) || empty($config['dbname']) || empty($config['username'])) {
                continue; // incomplete — skip silently
            }

            $driver  = (string) ($config['driver'] ?? 'mysql');
            $host    = (string) $config['host'];
            $port    = (int) ($config['port'] ?? 3306);
            $dbname  = (string) $config['dbname'];
            $charset = (string) ($config['charset'] ?? 'utf8mb4');

            $dsn = match ($driver) {
                'mysql'  => sprintf('mysql:host=%s;port=%d;dbname=%s;charset=%s', $host, $port, $dbname, $charset),
                'pgsql'  => sprintf('pgsql:host=%s;port=%d;dbname=%s', $host, $port, $dbname),
                'sqlsrv' => sprintf('sqlsrv:Server=%s,%d;Database=%s', $host, $port, $dbname),
                'sqlite' => sprintf('sqlite:%s', $dbname),
                default  => sprintf('%s:host=%s;dbname=%s', $driver, $host, $dbname),
            };

            $password = (string) ($config['password'] ?? '');
            if (!empty($config['encryptAtRest']) && $password !== '') {
                $securityClass = 'backend\\components\\Security';
                if (class_exists($securityClass)) {
                    try {
                        /** @phpstan-ignore-next-line */
                        $password = $securityClass::decryptSensitiveData($password);
                    } catch (\Throwable $ex) {
                        Yii::warning('DataDash: could not decrypt password for connection "' . $name . '" — ' . $ex->getMessage(), __METHOD__);
                        continue;
                    }
                }
            }

            $app->set($componentId, [
                'class'    => \yii\db\Connection::class,
                'dsn'      => $dsn,
                'username' => (string) ($config['username'] ?? ''),
                'password' => $password,
                'charset'  => $charset,
                'attributes' => [
                    \PDO::ATTR_PERSISTENT => (bool) ($config['persistent'] ?? false),
                ],
            ]);
        }
    }

    public function getDataService(): DataService
    {
        if ($this->dataService === null) {
            $this->dataService = new DataService();
        }

        return $this->dataService;
    }

    public function getDataServicesService(): DataServicesService
    {
        if ($this->dataServicesService === null) {
            $this->dataServicesService = new DataServicesService();
        }

        return $this->dataServicesService;
    }
}
