<?php

/**
 * Copyright 2024-2025 Simply.IN Sp. z o.o.
 *
 * NOTICE OF LICENSE
 *
 * Licensed under the EUPL-1.2 or later.
 * You may not use this work except in compliance with the Licence.
 *
 * Copy of the Licence is available at:
 * https://joinup.ec.europa.eu/software/page/eupl
 * It is bundled with this package in the file LICENSE.txt
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the Licence is distributed on an as is basis,
 * without warranties or conditions of any kind, either express or implied.
 * Check the Licence for the specific language governing permissions
 * and limitations under the License.
 *
 * @author   Simply.IN Sp. z o.o.
 * @copyright 2024-2025 Simply.IN Sp. z o.o.
 * @license   https://joinup.ec.europa.eu/software/page/eupl
 */

declare(strict_types=1);

namespace SimplyIn\Install;

use Configuration;
use Language;
use Module;
use OrderState;
use SimplyIn\BackOffice\Environment;
use SimplyIn\Webhook\WebhookDeduplicator;
use SimplyInEmailCache;
use SimplyInOrder;
use SimplyInOrderSync;
use SimplyInPayments;
use SimplyInPoint;
use Validate;

if (!defined('_PS_VERSION_')) {
    exit;
}

final class Installer
{
    /** @var list<string> */
    private const ORDER_STATES = [
        'SIMPLYIN_PAYMENT_STATUS_PENDING',
        'SIMPLYIN_PAYMENT_STATUS_CANCELED',
    ];

    /** @var array<string, array{en: string, pl: string}> */
    private const ORDER_STATE_NAMES = [
        'SIMPLYIN_PAYMENT_STATUS_PENDING' => [
            'en' => 'SimplyIN - Payment pending',
            'pl' => 'SimplyIN - Oczekiwanie na płatność',
        ],
        'SIMPLYIN_PAYMENT_STATUS_CANCELED' => [
            'en' => 'SimplyIN - Payment canceled',
            'pl' => 'SimplyIN - Płatność anulowana',
        ],
    ];

    public function __construct(private readonly Module $module)
    {
    }

    public function installAll(): bool
    {
        return $this->installDefaultConfiguration()
            && $this->registerHooks()
            && $this->installSql()
            && $this->installOrderStates();
    }

    public function installSql(): bool
    {
        return SimplyInOrder::installSql()
            && SimplyInPoint::installSql()
            && SimplyInOrderSync::installSql()
            && SimplyInEmailCache::installSql()
            && SimplyInPayments::installSql()
            && WebhookDeduplicator::installSql();
    }

    public function installDefaultConfiguration(): bool
    {
        // A fresh install must never start in Test — explicit, not just the enum's fallback.
        Configuration::updateValue('SIMPLYIN_ENVIRONMENT', Environment::default()->value);
        Configuration::updateValue('SIMPLYIN_TRANS_HISTORY_LENGTH_DAY', '180');
        Configuration::updateValue('SIMPLYIN_SAVE_CHECKBOX', false);
        Configuration::updateValue('SIMPLYIN_SWITCH_LASTCHANGE', '');
        Configuration::updateValue('SIMPLYIN_LOGISTICSPARTNERSORDER', '');

        Configuration::updateValue('SIMPLYIN_BAR_ENABLED', 0);
        Configuration::updateValue('SIMPLYIN_BAR_COLOR', 1);
        Configuration::updateValue('SIMPLYIN_BADGE_COLOR', 1);
        Configuration::updateValue('SIMPLYIN_ACCENT_COLOR', '#2d40f6');
        Configuration::updateValue('SIMPLYIN_FONT_COLOR', '#000000');

        return true;
    }

    public function registerHooks(): bool
    {
        foreach (HookRegistry::hooks() as $hook) {
            if (!$this->module->registerHook($hook)) {
                return false;
            }
        }

        return true;
    }

    public function installOrderStates(): bool
    {
        foreach (self::ORDER_STATES as $key) {
            if ($this->addOrderState($key, self::ORDER_STATE_NAMES[$key]) === false) {
                return false;
            }
        }

        return true;
    }

    /**
     * @param array<string, string> $names ISO code → localized name
     *
     * @return false|int the resolved OrderState id or false on failure
     */
    private function addOrderState(string $configKey, array $names): false|int
    {
        $existingId = Configuration::get($configKey);
        if ($existingId !== false && Validate::isInt($existingId)) {
            $existing = new OrderState((int) $existingId);
            if (Validate::isLoadedObject($existing)) {
                return (int) $existing->id;
            }
        }

        $orderState = new OrderState();
        foreach ($names as $isoCode => $name) {
            $langId = Language::getIdByIso($isoCode);
            if ($langId) {
                $orderState->name[(int) $langId] = $name;
            }
        }
        $orderState->send_email = false;
        $orderState->invoice = false;
        $orderState->logable = false;
        $orderState->unremovable = true;
        $orderState->color = '#002124';
        $orderState->module_name = $this->module->name;

        if (!$orderState->add() || !Configuration::updateValue($configKey, (int) $orderState->id)) {
            return false;
        }

        $logoSource = _PS_MODULE_DIR_ . $this->module->name . '/logo.gif';
        $logoTarget = _PS_IMG_DIR_ . 'os/' . (int) $orderState->id . '.gif';
        if (file_exists($logoSource)) {
            @copy($logoSource, $logoTarget);
        }

        return (int) $orderState->id;
    }
}
