<?php

namespace PortalPeople\magento\services;

use PortalPeople\magento\Module;
use PortalPeople\magento\models\Cart;
use Yii;
use yii\db\Expression;
use yii\db\Query;

class MonitoringService
{
    private const PARAM_FILE = '/var/www/vhosts/ahshub.dev.portalpeople.co.uk/httpdocs/backend/config/params-local.php';
    private const PARAM_PATH = ['plugins', 'magento', 'monitoring'];

    public function getMonitoringConfig(Module $module): array
    {
        return [
            'name' => 'Magento Orders',
            'checks' => [
                [
                    'id' => 'jobs-running',
                    'label' => 'Jobs Running',
                    'type' => 'callback',
                    'callback' => static function () use ($module): array {
                        return (new self())->jobsRunningCheck($module);
                    },
                ],
                [
                    'id' => 'last-run',
                    'label' => 'Last Run',
                    'type' => 'callback',
                    'callback' => static function () use ($module): array {
                        return (new self())->lastRunCheck($module);
                    },
                ],
                [
                    'id' => 'outstanding-to-import',
                    'label' => 'Outstanding to Import',
                    'type' => 'callback',
                    'callback' => static function () use ($module): array {
                        return (new self())->outstandingToImportCheck($module);
                    },
                ],
                [
                    'id' => 'not-in-netsuite',
                    'label' => 'Magento Orders not in NetSuite',
                    'type' => 'callback',
                    'callback' => static function () use ($module): array {
                        return (new self())->ordersNotInNetSuiteCheck($module);
                    },
                ],
            ],
        ];
    }

    public function recordImportRun(array $summary): void
    {
        $this->writeState([
            'last_run' => time(),
            'last_summary' => $summary,
        ]);
    }

    public function jobsRunningCheck(Module $module): array
    {
        if (!$module->isConfigured()) {
            return [
                'status' => 'warning',
                'message' => 'Magento integration is not configured.',
            ];
        }

        try {
            $stats = $this->queueStats();

            return [
                'status' => 'ok',
                'message' => sprintf('%d running, %d queued', $stats['running'], $stats['waiting']),
                'value' => $stats,
            ];
        } catch (\Throwable $e) {
            return [
                'status' => 'error',
                'message' => 'Unable to read queue state: ' . $e->getMessage(),
            ];
        }
    }

    public function lastRunCheck(Module $module): array
    {
        if (!$module->isConfigured()) {
            return [
                'status' => 'warning',
                'message' => 'Magento integration is not configured.',
            ];
        }

        $state = $this->readState();
        $lastRun = $state['last_run'] ?? null;
        $summary = $state['last_summary'] ?? null;

        if (!is_int($lastRun)) {
            return [
                'status' => 'warning',
                'message' => 'Magento import has not run yet.',
            ];
        }

        $ageSeconds = time() - $lastRun;
        $summaryText = is_array($summary)
            ? sprintf(' (%d imported, %d failed)', (int) ($summary['imported'] ?? 0), (int) ($summary['failed'] ?? 0))
            : '';

        return [
            'status' => $ageSeconds > 3600 ? 'warning' : 'ok',
            'message' => sprintf('Last run %s ago%s', $this->humanDuration($ageSeconds), $summaryText),
            'value' => [
                'timestamp' => $lastRun,
                'age_seconds' => $ageSeconds,
                'summary' => is_array($summary) ? $summary : null,
            ],
        ];
    }

    public function outstandingToImportCheck(Module $module): array
    {
        if (!$module->isConfigured()) {
            return [
                'status' => 'warning',
                'message' => 'Magento integration is not configured.',
            ];
        }

        try {
            $snapshotService = new OrderSnapshotService();
            $orders = $snapshotService->loadNewOrdersSnapshot($module, false);
            $count = count($orders['items'] ?? []);

            return [
                'status' => $count > 0 ? 'warning' : 'ok',
                'message' => $count > 0 ? sprintf('%d Magento order(s) waiting to import', $count) : 'No outstanding Magento orders to import',
                'value' => $count,
            ];
        } catch (\Throwable $e) {
            return [
                'status' => 'error',
                'message' => 'Unable to calculate outstanding imports: ' . $e->getMessage(),
            ];
        }
    }

    public function ordersNotInNetSuiteCheck(Module $module): array
    {
        if (!$module->isConfigured()) {
            return [
                'status' => 'warning',
                'message' => 'Magento integration is not configured.',
            ];
        }

        try {
            $query = Cart::find()
                ->where(['account_code' => 'GAR001'])
          //      ->andWhere(new Expression("json_value(`data`, '$.magento.order_no') IS NOT NULL"))
            //    ->andWhere(new Expression("json_value(`data`, '$.magento.order_no') <> ''"))
                ->andWhere(new Expression("(json_value(`data`, '$.netsuite.deliveryid') IS NULL OR json_value(`data`, '$.netsuite.deliveryid') = '')"));

            $count = (int) $query->count();

            return [
                'status' => $count > 0 ? 'warning' : 'ok',
                'message' => $count > 0 ? sprintf('%d Magento order(s) not in NetSuite', $count) : 'All imported Magento orders are present in NetSuite',
                'value' => $count,
            ];
        } catch (\Throwable $e) {
            return [
                'status' => 'error',
                'message' => 'Unable to query NetSuite sync state: ' . $e->getMessage(),
            ];
        }
    }

    private function queueStats(): array
    {
        $now = time();
        $table = '{{%queue}}';
        $magentoCondition = $this->magentoQueueCondition();

        $waiting = (int) (new Query())
            ->from($table)
            ->where(['channel' => 'default', 'reserved_at' => null, 'done_at' => null])
            ->andWhere($magentoCondition)
            ->count('*', Yii::$app->db);

        $running = (int) (new Query())
            ->from($table)
            ->where(['channel' => 'default', 'done_at' => null])
            ->andWhere($magentoCondition)
            ->andWhere(['not', ['reserved_at' => null]])
            ->count('*', Yii::$app->db);

        return [
            'waiting' => $waiting,
            'running' => $running,
            'match' => 'queue name or Magento job payload',
        ];
    }

    private function magentoQueueCondition(): array
    {
        return [
            'or',
            ['like', 'name', 'magento%', false],
            ['like', 'name', 'Import Magento%', false],
            ['like', 'job', 'PortalPeople\\magento\\jobs\\%', false],
            ['like', 'job', 'ImportMagentoOrderJob%', false],
        ];
    }

    private function readState(): array
    {
        $params = $this->readParams();

        return is_array($params['plugins']['magento']['monitoring'] ?? null)
            ? $params['plugins']['magento']['monitoring']
            : [];
    }

    private function writeState(array $state): void
    {
        $params = $this->readParams();

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

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

        $params['plugins']['magento']['monitoring'] = $state;

        $content = $this->renderParamsFile($params);
        @file_put_contents(self::PARAM_FILE, $content, LOCK_EX);

        if (Yii::$app !== null) {
            Yii::$app->params['plugins']['magento']['monitoring'] = $state;
        }
    }

    private function readParams(): array
    {
        if (!is_file(self::PARAM_FILE)) {
            return [];
        }

        $params = include self::PARAM_FILE;

        return is_array($params) ? $params : [];
    }

    private function renderParamsFile(array $params): string
    {
        return "<?php\nreturn " . var_export($params, true) . ";\n";
    }

    private function humanDuration(int $seconds): string
    {
        if ($seconds < 60) {
            return $seconds . 's';
        }

        if ($seconds < 3600) {
            return (string) round($seconds / 60) . 'm';
        }

        return round($seconds / 3600, 1) . 'h';
    }
}