<?php

use Bastion\ApplicationFactory;
use Cart\User;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;
use Openguru\OpenCartFramework\Application;
use Openguru\OpenCartFramework\OpenCart\Decorators\OcRegistryDecorator;
use Openguru\OpenCartFramework\Support\Arr;
use Psr\Log\LoggerInterface;

$sysLibPath = rtrim(DIR_SYSTEM, '/') . '/library/oc_telegram_shop';
$basePath = rtrim(DIR_APPLICATION, '/') . '/..';
if (is_readable($sysLibPath . '/oc_telegram_shop.phar')) {
    require_once "phar://{$sysLibPath}/oc_telegram_shop.phar/vendor/autoload.php";
} elseif (is_dir("$basePath/oc_telegram_shop")) {
    require_once "$basePath/oc_telegram_shop/vendor/autoload.php";
} else {
    throw new RuntimeException('Unable to locate application directory.');
}

/**
 * @property Document $document
 * @property Loader $load
 * @property Config $config
 * @property Language $language
 * @property Request $request
 * @property Session $session
 * @property ModelSettingSetting $model_setting_setting
 * @property Response $response
 * @property Url $url
 * @property ModelToolImage $model_tool_image
 * @property ModelCatalogProduct $model_catalog_product
 * @property User $user
 * @property ModelCustomerCustomerGroup $model_customer_customer_group
 * @property ModelLocalisationOrderStatus $model_localisation_order_status
 * @property ModelDesignBanner $model_design_banner
 * @property DB $db
 * @property Log $log
 */
class ControllerExtensionModuleTgshop extends Controller
{
    private static array $themes = [
        'light' => 'Светлая (light)',
        'dark' => 'Тёмная (dark)',
        'cupcake' => 'Капкейк (cupcake)',
        'bumblebee' => 'Шмель (bumblebee)',
        'emerald' => 'Изумруд (emerald)',
        'corporate' => 'Корпоративная (corporate)',
        'synthwave' => 'Синтвейв (synthwave)',
        'retro' => 'Ретро (retro)',
        'cyberpunk' => 'Киберпанк (cyberpunk)',
        'valentine' => 'Валентинка (valentine)',
        'halloween' => 'Хэллоуин (halloween)',
        'garden' => 'Сад (garden)',
        'forest' => 'Лес (forest)',
        'aqua' => 'Аква (aqua)',
        'lofi' => 'Лоу-фай (lofi)',
        'pastel' => 'Пастель (pastel)',
        'fantasy' => 'Фэнтези (fantasy)',
        'wireframe' => 'Каркас (wireframe)',
        'black' => 'Чёрная (black)',
        'luxury' => 'Люкс (luxury)',
        'dracula' => 'Дракула (dracula)',
        'cmyk' => 'CMYK (cmyk)',
        'autumn' => 'Осень (autumn)',
        'business' => 'Бизнес (business)',
        'acid' => 'Кислотная (acid)',
        'lemonade' => 'Лимонад (lemonade)',
        'night' => 'Ночная (night)',
        'coffee' => 'Кофейная (coffee)',
        'winter' => 'Зимняя (winter)',
        'dim' => 'Тусклая (dim)',
        'nord' => 'Нордическая (nord)',
        'sunset' => 'Закат (sunset)',
        'caramellatte' => 'Карамель-латте (caramellatte)',
        'abyss' => 'Бездна (abyss)',
        'silk' => 'Шёлк (silk)',
    ];

    private array $error = [];

    public function __construct($registry)
    {
        parent::__construct($registry);

        $this->load->language('extension/module/tgshop');
        $this->load->model('setting/setting');
        $this->load->model('tool/image');
        $this->load->model('catalog/product');
        $this->load->model('catalog/category');
        $this->load->model('localisation/order_status');
        $this->load->model('customer/customer_group');
    }

    public function index(): void
    {
        $this->runMaintenanceTasks();
        $this->injectAssets();
        $this->injectVueJs();
        $this->showConfigPage();
    }

    private function showConfigPage(): void
    {
        $data = [];
        $this->document->setTitle($this->language->get('heading_title'));

        $this->baseData($data);

        $data['order_statuses'] = $this->getOrderStatuses();
        $data['customer_groups'] = $this->getCustomerGroups();
        $data['themes'] = self::$themes;
        $data['telecart_module_version'] = module_version();
        $data['shop_base_url'] = HTTPS_CATALOG;

        $data['action'] = $this->url->link(
            'extension/module/tgshop',
            'user_token=' . $this->session->data['user_token'],
            true
        );

        $this->response->setOutput($this->load->view('extension/module/tgshop', $data));
    }

    public function handle(): void
    {
        $logger = $this->createLogger();

        $this
            ->createApplication($logger)
            ->bootAndHandleRequest();
    }

    protected function validate(): bool
    {
        if (! $this->user->hasPermission('modify', 'extension/module/tgshop')) {
            $this->error['telecart_error_warning'] = $this->language->get('error_permission');
        }

        return ! $this->error;
    }

    private function baseData(array &$data): void
    {
        $this->document->setTitle($this->language->get('heading_title'));

        $data['header'] = $this->load->controller('common/header');
        $data['column_left'] = $this->load->controller('common/column_left');
        $data['footer'] = $this->load->controller('common/footer');

        $data['cancel'] = $this->url->link(
            'marketplace/extension',
            'user_token=' . $this->session->data['user_token'] . '&type=module',
            true
        );

        $data = array_merge($data, $this->error);

        if (isset($this->session->data['success'])) {
            $data['success'] = $this->session->data['success'];

            unset($this->session->data['success']);
        } else {
            $data['success'] = '';
        }

        $data['user_token'] = $this->session->data['user_token'];
    }

    private function getCustomerGroups(): array
    {
        $map = [];

        foreach ($this->model_customer_customer_group->getCustomerGroups() as $customer_group) {
            $map[(int) $customer_group['customer_group_id']] = $customer_group['name'];
        }

        return $map;
    }

    private function getOrderStatuses(): array
    {
        $statuses = $this->model_localisation_order_status->getOrderStatuses();
        $map = [];

        foreach ($statuses as $item) {
            $map[(int) $item['order_status_id']] = $item['name'];
        }

        return $map;
    }

    private function injectVueJs(): void
    {
        $appDir = rtrim(DIR_APPLICATION, '/');
        if (file_exists("$appDir/view/javascript/telecart/telecart.js")) {
            $hash = file_get_contents($appDir . '/view/javascript/telecart/checksum.hash');
            $this->document->addScript('view/javascript/telecart/telecart.js?v=' . $hash);
            $this->document->addStyle('view/javascript/telecart/telecart.css?v=' . $hash);
        } elseif (file_exists("$appDir/view/integration.js")) {
            $this->document->addScript('view/integration.js');
        } else {
            throw new RuntimeException('Unable to load Vuejs frontend.');
        }
    }

    private function createApplication(LoggerInterface $logger): Application
    {
        $json = $this->model_setting_setting->getSetting('module_telecart');
        if (! isset($json['module_telecart_settings'])) {
            $json['module_telecart_settings'] = [];
        }

        $items = Arr::mergeArraysRecursively($json['module_telecart_settings'], [
            'app' => [
                'shop_base_url' => HTTPS_CATALOG, // for catalog: HTTPS_SERVER, for admin: HTTPS_CATALOG
                'language_id' => (int) $this->config->get('config_language_id'),
            ],
            'paths' => [
                'images' => DIR_IMAGE,
            ],
            'logs' => [
                'path' => DIR_LOGS,
            ],
            'database' => [
                'host' => DB_HOSTNAME,
                'database' => DB_DATABASE,
                'username' => DB_USERNAME,
                'password' => DB_PASSWORD,
                'prefix' => DB_PREFIX,
                'port' => (int) DB_PORT,
            ],
            'store' => [
                'oc_store_id' => 0,
                'oc_default_currency' => $this->config->get('config_currency'),
                'oc_config_tax' => filter_var($this->config->get('config_tax'), FILTER_VALIDATE_BOOLEAN),
            ],
            'orders' => [
                'oc_customer_group_id' => (int) $this->config->get('config_customer_group_id'),
            ],
            'telegram' => [
                'mini_app_url' => rtrim(HTTPS_CATALOG, '/') . '/image/catalog/tgshopspa/#/',
            ],
        ]);

        $app = ApplicationFactory::create($items);
        $app->bind(OcRegistryDecorator::class, fn() => new OcRegistryDecorator($this->registry));
        $app->setLogger($logger);

        return $app;
    }

    private function runMaintenanceTasks(): void
    {
        $logger = $this->createLogger();

        try {
            $this->createApplication($logger)->runMaintenanceTasks();
        } catch (Throwable $exception) {
            $logger->error($exception->getMessage(), ['exception' => $exception]);
        }
    }

    private function createLogger(bool $debug = false): Logger
    {
        $log = new Logger('TeleCart_Admin', [], [], new DateTimeZone('UTC'));
        $log->pushHandler(
            new RotatingFileHandler(
                DIR_LOGS . '/telecart.log', 14, $debug ? Logger::DEBUG : Logger::INFO
            ),
        );

        return $log;
    }

    private function injectAssets(): void
    {
        $this->document->addScript('view/javascript/summernote/summernote.js');
        $this->document->addStyle('view/javascript/summernote/summernote.css');
    }
}
