<?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\Bootstrap;

use Configuration;
use Context;
use Simplyin;
use SimplyIn\Api\EncryptionService;
use SimplyIn\Api\SimplyInApiClient;
use SimplyIn\Api\SimplyInApiClientFactory;
use SimplyIn\Auth\RsaRegistrar;
use SimplyIn\Auth\RsaSigner;
use SimplyIn\Auth\SecretCipher;
use SimplyIn\BackOffice\AdminOrderDisplay;
use SimplyIn\BackOffice\ConfigurationRepository;
use SimplyIn\BackOffice\OrdersGridDecorator;
use SimplyIn\BackOffice\OrderStatusSync;
use SimplyIn\Carrier\CarrierConfigRegistry;
use SimplyIn\Checkout\AccountUpdateHandler;
use SimplyIn\Checkout\CheckoutSessionRepository;
use SimplyIn\Checkout\LegacyCheckoutApi;
use SimplyIn\Checkout\LegacyEmailCache;
use SimplyIn\Checkout\LegacyOrderDataFetcher;
use SimplyIn\Checkout\PrestaShopCustomerEmailProvider;
use SimplyIn\Front\AssetRegistrar;
use SimplyIn\Front\JsHeaderDataBuilder;
use SimplyIn\Front\OpcDetector;
use SimplyIn\Payment\OrderConfirmationRenderer;
use SimplyIn\Payment\OrderStateUpdater;
use SimplyIn\Payment\PaymentLogoResolver;
use SimplyIn\Payment\PaymentMethodsProvider;
use SimplyIn\Payment\PaymentOptionsBuilder;
use SimplyIn\Payment\PaymentStatusChecker;
use SimplyIn\Security\TokenService;
use SimplyIn\Service\EncryptedTrackingSender;
use SimplyIn\Service\MerchantSettingsSync;
use SimplyIn\Service\OrderSync\LegacyOrderSyncQueue;
use SimplyIn\Service\OrderSync\OrderCreationHandler;
use SimplyIn\Service\OrderSync\OrderSyncService;
use SimplyIn\Service\TrackingNumberSync;
use SimplyIn\Session\PrestashopSessionAdapter;
use SimplyIn\Session\SessionHelper;
use SimplyIn\Webhook\WebhookSecretStore;

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

final class ModuleBootstrap
{
    public function __construct(
        private readonly Simplyin $module,
    ) {
    }

    public function bootstrap(): void
    {
        $module = $this->module;
        $context = Context::getContext();

        $module->merchantApiKey = (string) Configuration::get('SIMPLYIN_SECRET_KEY');
        $module->merchand_api_key = $module->merchantApiKey;

        $sessionAdapter = new PrestashopSessionAdapter($context->cookie, $context->cart);
        $module->simplyin_session = $sessionAdapter;

        // RSA request auth (clean RSA-only). One shared signer/registrar so state (memory cache,
        // once-per-process guard) stays consistent across every API client built this request.
        $cipher = new SecretCipher(_COOKIE_KEY_);
        $rsaSigner = new RsaSigner($cipher);
        $rsaRegistrar = new RsaRegistrar(
            $rsaSigner,
            rtrim((string) $module->backend_url, '/') . '/',
            $module->merchantApiKey,
            (string) $context->shop->getBaseURL(true),
        );
        $module->rsaSigner = $rsaSigner;
        $module->rsaRegistrar = $rsaRegistrar;

        $module->apiClient = SimplyInApiClientFactory::fromPrestaShop($module, $context, null, $rsaSigner, $rsaRegistrar);

        $clientFactory = static function (?string $override) use ($module, $rsaSigner, $rsaRegistrar): SimplyInApiClient {
            $hasOverride = $override !== null && $override !== '';

            // A NEW/override API key (admin testing a key) must authenticate with THAT key, not with
            // an RSA credential registered against the current one — so skip the signer in that case.
            return SimplyInApiClientFactory::fromPrestaShop(
                $module,
                Context::getContext(),
                $hasOverride ? $override : null,
                $hasOverride ? null : $rsaSigner,
                $hasOverride ? null : $rsaRegistrar,
            );
        };

        $module->merchantSettingsSync = new MerchantSettingsSync(
            (string) $module->version,
            $clientFactory,
            new WebhookSecretStore($cipher),
        );
        if ($module->merchantApiKey !== '') {
            $module->simplyInUpdateMerchantSettings();
        }

        $module->opcDetector = new OpcDetector();
        $module->assetRegistrar = new AssetRegistrar($module->opcDetector);
        $module->tokenService = new TokenService(
            $module->name,
            (string) $module->version,
            _COOKIE_KEY_,
        );
        $module->jsHeaderDataBuilder = new JsHeaderDataBuilder(
            $module->opcDetector,
            $module->tokenService,
            $sessionAdapter,
        );
        $module->paymentStatusChecker = new PaymentStatusChecker($module->tokenService, $module->apiClient);

        $logoResolver = new PaymentLogoResolver(dirname(__DIR__, 2) . '/views/img/providers');
        $paymentMethodsProvider = new PaymentMethodsProvider($module->apiClient, $sessionAdapter);
        $module->paymentOptionsBuilder = new PaymentOptionsBuilder(
            $logoResolver,
            $sessionAdapter,
            $paymentMethodsProvider,
        );
        $module->orderConfirmationRenderer = new OrderConfirmationRenderer($sessionAdapter);
        $module->checkoutSessionRepository = new CheckoutSessionRepository(
            $sessionAdapter,
            $module->opcDetector,
        );

        $configurationRepository = new ConfigurationRepository();
        $module->orderSyncService = new OrderSyncService(
            $module->apiClient,
            $configurationRepository,
        );
        $module->orderCreationHandler = new OrderCreationHandler(
            $sessionAdapter,
            new LegacyCheckoutApi($module->apiClient),
            new LegacyOrderDataFetcher(),
            new PrestaShopCustomerEmailProvider(),
            new LegacyEmailCache(),
            new LegacyOrderSyncQueue($module->orderSyncService),
        );

        $encryptedTrackingSender = new EncryptedTrackingSender(
            new EncryptionService(),
            $module->apiClient,
        );
        $module->trackingNumberSync = new TrackingNumberSync($encryptedTrackingSender);
        $module->carrierConfigRegistry = new CarrierConfigRegistry();
        $module->sessionHelper = new SessionHelper($sessionAdapter);

        $orderStatusSync = new OrderStatusSync($module->apiClient);
        $module->adminOrderDisplay = new AdminOrderDisplay($orderStatusSync);
        $module->orderStateUpdater = new OrderStateUpdater();
        $module->accountUpdateHandler = new AccountUpdateHandler(
            $sessionAdapter,
            $module->checkoutSessionRepository,
        );
        $module->ordersGridDecorator = new OrdersGridDecorator($module);
    }
}
