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

use Configuration;
use Context;
use Country;
use Module;
use SimplyIn\BackOffice\SaveCheckboxState;
use SimplyIn\Security\TokenService;
use SimplyIn\Session\SimplyInSessionInterface;
use SimplyInEmailCache;
use SimplyInPayments;
use SimplyInPoint;
use Tools;

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

final class JsHeaderDataBuilder
{
    private OpcDetector $opcDetector;

    private TokenService $tokenService;

    private SimplyInSessionInterface $session;

    public function __construct(
        OpcDetector $opcDetector,
        TokenService $tokenService,
        SimplyInSessionInterface $session,
    ) {
        $this->opcDetector = $opcDetector;
        $this->tokenService = $tokenService;
        $this->session = $session;
    }

    /**
     * @param array<string, mixed> $override
     *
     * @return array<string, mixed>
     */
    public function build(Module $module, array $override = []): array
    {
        $context = Context::getContext();
        $customer = $context->customer ?? null;

        $hidePhoneField = false;
        $newAccountPhone = false;
        if ($customer && !empty($customer->email)) {
            $hidePhoneField = SimplyInEmailCache::checkUserExist($customer->email);
            $newAccountPhone = $this->resolveNewAccountPhone();
        }

        $point = ($context->cart && $context->cart->id)
            ? SimplyInPoint::getByIdCart((int) $context->cart->id)
            : new SimplyInPoint();

        $idAddressDelivery = $this->session->get('simplyin_id_address_delivery', false);
        $authToken = (string) $this->session->get('simplyin_auth_token', '');
        $apiLogged = trim($authToken) !== '';
        $idCarrier = (int) ($context->cart->id_carrier ?? 0);
        $checkout = $this->opcDetector->detect();
        $needLogin = $hidePhoneField && !$apiLogged;
        $controller = (string) Tools::getValue('controller');

        $return = [
            'simplyin' => [
                'checkout' => $checkout,
                'controller' => $controller,
                'ajax_token' => $this->tokenService->getAjaxToken(),
                'cart_token' => (string) $module->getCartToken(),
                'files_url' => _MODULE_DIR_ . $module->name . '/',
                'id_carrier' => $idCarrier,
                // Bridges the checkout address form's numeric id_country (PrestaShop's
                // internal country id, all the ".js-country" select carries) to the
                // ISO alpha-2 code the phone widget's own country dropdown is keyed
                // on, so the widget can track the selected address country.
                'country_iso_by_id' => $this->buildCountryIsoById(),
                'controllers' => [
                    'ajax' => $context->link->getModuleLink('simplyin', 'ajax'),
                    'payment_ajax' => $context->link->getModuleLink('simplyin', 'paymentajax'),
                ],
                'customer_email' => $this->resolveCustomerEmail(),
                'customer' => [
                    'need_login' => $needLogin,
                    'has_selected_address' => (bool) $idAddressDelivery,
                    'is_guest' => $customer ? $customer->isGuest() : false,
                    'logged' => $customer ? $customer->isLogged() : false,
                    'has_token' => $apiLogged,
                    'email' => $customer ? $customer->email : '',
                    'point' => [
                        'label' => $point->label,
                        'locker_id' => $point->lockerId,
                        'address' => $point->address,
                        'address_name' => $point->addressName,
                    ],
                ],
                'currentLanguage' => $context->language,
                'display' => [
                    'bar' => (bool) Configuration::get('SIMPLYIN_BAR_ENABLED'),
                    'bar_color' => (bool) Configuration::get('SIMPLYIN_BAR_COLOR'),
                    'badge_color' => (bool) Configuration::get('SIMPLYIN_BADGE_COLOR'),
                    'accent_color' => Configuration::get('SIMPLYIN_ACCENT_COLOR') ?: '#2d40f6',
                    'font_color' => Configuration::get('SIMPLYIN_FONT_COLOR') ?: '#000000',
                ],
                'labels' => $this->buildLabels($module),
                'hide_phone_field' => $hidePhoneField,
                'new_account_phone' => $newAccountPhone,
                'save_checkbox' => SaveCheckboxState::isCheckedByDefault(),
                'select_customer_privacy' => false,
                'select_psgdpr' => false,
                'submit_guest_form' => false,
            ],
        ];

        if ($controller === 'orderconfirmation') {
            $return = $this->applyOrderConfirmationOverride($module, $return, $checkout);
        }

        if (Configuration::get('SIMPLYIN_PAYMENTS')) {
            $return = $this->applyPaymentsChannel($module, $return);
        }

        if (!empty($override)) {
            $return = array_merge_recursive($return, $override);
        }

        return $return;
    }

    /**
     * @return array<string, string>
     */
    private function buildLabels(Module $module): array
    {
        return [
            'By paying, I accept the terms and [conditions] and [privacy policy] of %s' => $module->l('By paying, I accept the terms and [conditions] and [privacy policy] of %s'),
            'Please select a payment method' => $module->l('Please select a payment method'),
            'BLIK code rejected' => $module->l('BLIK code rejected'),
            'bar_caption' => $module->l('Here you complete your purchase with'),
            'cancel' => $module->l('Cancel'),
            'change' => $module->l('Change'),
            'code_invalid' => $module->l('Invalid code'),
            'confirm_delete' => $module->l('Confirm delete address?'),
            'confirm_profile' => $module->l('Confirm profile'),
            'data_completed' => $module->l('Data completed'),
            'delete' => $module->l('Delete'),
            'delete_header' => $module->l('Delete address'),
            'code_consumed' => $module->l('Something went wrong finishing sign-in. Please request a new code.'),
            'edit' => $module->l('Edit'),
            'generic_error' => $module->l('Something went wrong. Please try again.'),
            'Invalid BLIK code' => $module->l('Invalid BLIK code'),
            'Invalid tokenization response' => $module->l('Invalid tokenization response'),
            'Problem processing card' => $module->l('Problem processing card'),
            'Problem with BLIK processing' => $module->l('Problem with BLIK processing'),
        ];
    }

    /**
     * @return array<int, string>
     */
    private function buildCountryIsoById(): array
    {
        $idLang = (int) Context::getContext()->language->id;
        $map = [];
        foreach (Country::getCountries($idLang, true) as $country) {
            $map[(int) $country['id_country']] = (string) $country['iso_code'];
        }

        return $map;
    }

    /**
     * @param array<string, mixed> $return
     *
     * @return array<string, mixed>
     */
    private function applyOrderConfirmationOverride(Module $module, array $return, string $checkout): array
    {
        $ajaxSend = true;
        $idCart = (int) Tools::getValue('id_cart');
        $idModule = (int) Tools::getValue('id_module');

        $ajaxToken = (string) $module->getAjaxToken();
        $cartToken = (string) $module->getCartToken($idCart);
        $paymentCheckToken = (string) $module->getPaymentCheckToken($ajaxToken, $cartToken);

        if ($idModule) {
            $paymentInfo = SimplyInPayments::getPaymentInfo($idCart);
            $status = $paymentInfo ? $paymentInfo->status : null;

            $instance = Module::getInstanceById($idModule);
            if ($instance && $instance->name === 'simplyin') {
                $ajaxSend = false;
                $return['simplyin'] = [
                    'checkout' => $checkout,
                    'order_sended' => true,
                    'controllers' => [
                        'payment_ajax' => Context::getContext()->link->getModuleLink('simplyin', 'paymentajax'),
                    ],
                    'files_url' => _MODULE_DIR_ . $module->name . '/',
                    'id_cart' => $idCart,
                    'id_module' => $idModule,
                    'key' => Tools::getValue('key'),
                    'ajax_token' => $ajaxToken,
                    'cart_token' => $cartToken,
                    'payment_check_token' => $paymentCheckToken,
                    'payment_status' => $status,
                ];
            }
        }

        if ($idCart && $ajaxSend && $this->isSimplyInAuthenticated()) {
            $return['simplyin']['order'] = [
                'id_cart' => $idCart,
                'order_token' => $this->tokenService->getOrderToken($idCart),
            ];
        }

        return $return;
    }

    /**
     * @param array<string, mixed> $return
     *
     * @return array<string, mixed>
     */
    private function applyPaymentsChannel(Module $module, array $return): array
    {
        $context = Context::getContext();
        $cartId = (int) ($context->cart->id ?? 0);
        $ajaxToken = $module->getAjaxToken();
        $cartToken = $module->getCartToken($cartId);

        $return['simplyin'][''] = [
            'check_payment_ajax' => $context->link->getModuleLink('simplyin', 'paymentajax'),
            'id_cart' => $cartId,
            'id_module' => $module->id,
            'ajax_token' => $ajaxToken,
            'cart_token' => $cartToken,
            'payment_check_token' => $this->tokenService->getPaymentCheckToken($ajaxToken, $cartToken),
            'status' => SimplyInPayments::getPaymentInfo($cartId),
        ];

        return $return;
    }

    private function resolveNewAccountPhone(): mixed
    {
        $phone = $this->session->get('new_account_phone');

        return empty($phone) ? false : $phone;
    }

    private function resolveCustomerEmail(): string
    {
        $email = $this->session->get('simplyin_email');
        $token = $this->session->get('simplyin_auth_token');
        if (!empty($email) && !empty($token)) {
            return (string) $email;
        }

        return '';
    }

    private function isSimplyInAuthenticated(): bool
    {
        $token = $this->session->get('simplyin_auth_token');
        if (!empty($token)) {
            return true;
        }
        $phone = $this->session->get('new_account_phone');

        return !empty($phone);
    }
}
