<?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 Address;
use Configuration;
use Context;
use Country;
use Simplyin;

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

final class NewAccountFormRenderer
{
    public function __construct(
        private readonly Context $context,
        private readonly Simplyin $module,
    ) {
    }

    public function render(string $checkoutType): string
    {
        $countries = $this->loadCountries();

        $this->context->smarty->assign([
            'module_path' => $this->module->getPathUri(),
            'countries' => $countries,
            'checkout_type' => $checkoutType,
        ]);

        $docs = json_decode((string) Configuration::get('SIMPLYIN_DOCS_INFO'), true);
        if (!is_array($docs) || $docs === []) {
            $docs = [
                'tc-b2c-pl' => 'https://simply.in/terms-b2c/',
                'gdpr-pl' => 'https://simply.in/privacy-policy/',
            ];
        }

        [$prefix, $phone, $checked] = $this->resolvePhone($countries);
        $selectedCountryCode = $this->matchCountryCode($countries, $prefix);

        $addressIso = $this->addressCountryIso();
        if ($addressIso !== null) {
            foreach ($countries as $country) {
                if (
                    strcasecmp((string) ($country['code'] ?? ''), $addressIso) === 0
                    && (string) ($country['dial_code'] ?? '') === $prefix
                ) {
                    $selectedCountryCode = (string) $country['code'];

                    break;
                }
            }
        }

        $this->context->smarty->assign([
            'terms_link' => $docs['tc-b2c-pl'] ?? 'https://simply.in/terms-b2c/',
            'privacy_link' => $docs['gdpr-pl'] ?? 'https://simply.in/privacy-policy/',
            'selected_prefix' => $prefix,
            'selected_country_code' => $selectedCountryCode,
            'phone' => $phone,
            'checked' => $checked,
        ]);

        return (string) $this->context->smarty->fetch(
            _PS_MODULE_DIR_ . 'simplyin/views/templates/front/create_account.tpl',
        );
    }

    /**
     * @return array<int, array{code: string, dial_code: string, name?: string}>
     */
    private function loadCountries(): array
    {
        $path = _PS_MODULE_DIR_ . 'simplyin/views/json/countries.json';
        if (!is_readable($path)) {
            return [];
        }
        $decoded = json_decode((string) file_get_contents($path), true);

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

    /**
     * @param array<int, array<string, string>> $countries
     *
     * @return array{0: string, 1: string, 2: bool}
     */
    private function resolvePhone(array $countries): array
    {
        $prefix = '+48';
        $checked = !Configuration::get('SIMPLYIN_SAVE_CHECKBOX');

        $cart = $this->context->cart;
        if ($cart === null) {
            return $this->resolveStoredPhone($prefix, (bool) $checked) ?? [$prefix, '', (bool) $checked];
        }
        $address = new Address((int) $cart->id_address_delivery);

        if ((string) $address->phone === '') {
            $stored = $this->resolveStoredPhone($prefix, (bool) $checked);
            if ($stored !== null) {
                return $stored;
            }
        }

        $idCountry = (int) $address->id_country;
        if ($idCountry) {
            $addressIso = (string) (new Country($idCountry))->iso_code;
            if ($addressIso !== '') {
                foreach ($countries as $country) {
                    if (isset($country['code']) && strcasecmp((string) $country['code'], $addressIso) === 0) {
                        $prefix = (string) $country['dial_code'];

                        break;
                    }
                }
            }
        }

        $raw = (string) $address->phone;
        if ($raw === '') {
            return [$prefix, '', (bool) $checked];
        }

        $clean = preg_replace('/\s+/', '', $raw) ?? '';
        $longest = 0;
        $matchedPrefix = null;
        foreach ($countries as $country) {
            $countryPrefix = preg_replace('/\s+/', '', (string) ($country['dial_code'] ?? '')) ?? '';
            if ($countryPrefix !== '' && strpos($clean, $countryPrefix) === 0 && strlen($countryPrefix) > $longest) {
                $matchedPrefix = $countryPrefix;
                $longest = strlen($countryPrefix);
            }
        }

        if ($matchedPrefix !== null) {
            return [$matchedPrefix, substr($clean, $longest), (bool) $checked];
        }

        return [$prefix, $raw, (bool) $checked];
    }

    private function addressCountryIso(): ?string
    {
        $cart = $this->context->cart;
        if ($cart === null || !(int) $cart->id_address_delivery) {
            return null;
        }
        $address = new Address((int) $cart->id_address_delivery);
        if (!(int) $address->id_country) {
            return null;
        }
        $iso = (string) (new Country((int) $address->id_country))->iso_code;

        return $iso !== '' ? $iso : null;
    }

    /**
     * Previously stored new-account phone ("+48 123456789"), or null when absent.
     * Used only as a fallback when the delivery address carries no phone.
     *
     * @return null|array{0: string, 1: string, 2: bool}
     */
    private function resolveStoredPhone(string $defaultPrefix, bool $checked): ?array
    {
        $phone = $this->module->getNewAccountPhone();
        if ($phone === false || $phone === '' || $phone === '0') {
            return null;
        }

        $parts = explode(' ', (string) $phone, 2);
        if (count($parts) === 2) {
            return [$parts[0], $parts[1], true];
        }

        return [$defaultPrefix, (string) $phone, $checked];
    }

    /**
     * @param array<int, array<string, string>> $countries
     */
    private function matchCountryCode(array $countries, string $prefix): string
    {
        foreach ($countries as $country) {
            if (($country['dial_code'] ?? null) === $prefix) {
                return (string) ($country['code'] ?? 'PL');
            }
        }

        return 'PL';
    }
}
