<?php
/**
 * Copyright since 2025 InPost S.A.
 *
 * For the full license information, please view the LICENSE file bundled with the module.
 *
 * @author InPost S.A.
 * @copyright since 2025 InPost S.A.
 * @license MIT
 */

declare(strict_types=1);

namespace InPost\International;

use InPost\International\Enum\StringEnum;
use InPost\International\Translation\TranslatableInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

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

/**
 * @method static self Poland()
 * @method static self France()
 * @method static self Belgium()
 * @method static self Netherlands()
 * @method static self Spain()
 * @method static self Portugal()
 * @method static self Italy()
 * @method static self Luxembourg()
 * @method static self Hungary()
 * @method static self Austria()
 */
final class Country extends StringEnum implements TranslatableInterface
{
    private const POLAND = 'PL';
    private const FRANCE = 'FR';
    private const BELGIUM = 'BE';
    private const NETHERLANDS = 'NL';
    private const SPAIN = 'ES';
    private const PORTUGAL = 'PT';
    private const ITALY = 'IT';
    private const LUXEMBOURG = 'LU';
    private const HUNGARY = 'HU';
    private const AUSTRIA = 'AT';

    public static function getByPhoneNumberPrefix(string $prefix): ?self
    {
        foreach (self::cases() as $country) {
            if ($prefix === $country->getPhonePrefix()) {
                return $country;
            }
        }

        return null;
    }

    public function trans(TranslatorInterface $translator, string $locale = null): string
    {
        switch ($this) {
            case self::Poland():
                return $translator->trans('Poland', [], 'Modules.Inpostinternational.Country', $locale);
            case self::France():
                return $translator->trans('France', [], 'Modules.Inpostinternational.Country', $locale);
            case self::Belgium():
                return $translator->trans('Belgium', [], 'Modules.Inpostinternational.Country', $locale);
            case self::Netherlands():
                return $translator->trans('Netherlands', [], 'Modules.Inpostinternational.Country', $locale);
            case self::Spain():
                return $translator->trans('Spain', [], 'Modules.Inpostinternational.Country', $locale);
            case self::Portugal():
                return $translator->trans('Portugal', [], 'Modules.Inpostinternational.Country', $locale);
            case self::Italy():
                return $translator->trans('Italy', [], 'Modules.Inpostinternational.Country', $locale);
            case self::Luxembourg():
                return $translator->trans('Luxembourg', [], 'Modules.Inpostinternational.Country', $locale);
            case self::Hungary():
                return $translator->trans('Hungary', [], 'Modules.Inpostinternational.Country', $locale);
            case self::Austria():
                return $translator->trans('Austria', [], 'Modules.Inpostinternational.Country', $locale);
            default:
                return $this->name;
        }
    }

    public function getPhonePrefix(): string
    {
        switch ($this) {
            case self::Poland():
                return '+48';
            case self::France():
                return '+33';
            case self::Belgium():
                return '+32';
            case self::Netherlands():
                return '+31';
            case self::Spain():
                return '+34';
            case self::Portugal():
                return '+351';
            case self::Italy():
                return '+39';
            case self::Luxembourg():
                return '+352';
            case self::Hungary():
                return '+36';
            case self::Austria():
                return '+43';
            default:
                throw new \LogicException('Not implemented.');
        }
    }

    public function getPhoneNumberPattern(): string
    {
        switch ($this) {
            case self::Poland():
            case self::Netherlands():
            case self::Hungary():
                return '/^\d{9}$/';
            case self::France():
            case self::Portugal():
                return '/^[1-9]\d{8}$/';
            case self::Belgium():
                return '/^[1-9]\d{7,8}$/';
            case self::Spain():
                return '/^[6-9]\d{8}$/';
            case self::Italy():
                return '/^3\d{8,10}$/';
            case self::Luxembourg():
                return '/^\d{3,11}$/';
            case self::Austria():
                return '/^\d{4,13}$/';
            default:
                throw new \LogicException('Not implemented.');
        }
    }

    public function getAddressPattern(): string
    {
        switch ($this) {
            case self::Poland():
            case self::Austria():
                return '/^(?P<street>[^\/]*)\s+(?P<house_number>\d+.*?)(?:\s*\/\s*(?P<flat_number>.*))?$/';
            case self::France():
                return '/^(?:(?:appt\.?|appartement)\s+(?P<flat_number>\d+[^,]?),?\s+)?(?P<house_number>\d+[^,]?),?\s+(?P<street>.*)$/i';
            case self::Belgium():
                return '/^(?P<street>.*?)\s+(?P<house_number>\d+\S*?)(?:\s+(?:bus|bte)\s+(?P<flat_number>.*))?$/';
            case self::Netherlands():
            case self::Portugal():
                return '/^(?P<street>.*?)\s+(?P<house_number>\d+.*?)(?:\s*\-\s*(?P<flat_number>\d+.*))?$/';
            case self::Spain():
                return '/^(?P<street>.*?)\s+(?P<house_number>\d+[^,]*)(?:,\s+(?P<flat_number>.*))?$/';
            case self::Italy():
            case self::Hungary():
                return '/^(?P<street>.*)\s+(?P<house_number>\d+.*)$/';
            case self::Luxembourg():
                return '/^(?P<house_number>\d+\S*?),?\s+(?P<street>.*)$/';
            default:
                throw new \LogicException('Not implemented.');
        }
    }

    public function formatStreetAddress(string $street, string $buildingNumber): string
    {
        switch ($this) {
            case self::France():
            case self::Luxembourg():
                return trim(sprintf('%s %s', $buildingNumber, $street));
            default:
                return trim(sprintf('%s %s', $street, $buildingNumber));
        }
    }
}
