<?php

declare(strict_types=1);

namespace App\Support;

/**
 * Канонический справочник субъектов РФ (1..89) — PHP-зеркало
 * resources/js/constants/regions.ts (конституционный порядок, ст. 65).
 * Sentinel 0 «Вся РФ» не входит (= NULL subject_code / пустой regions).
 *
 * ВАЖНО: при правке regions.ts синхронно править этот файл (тест RegionTagResolverTest
 * «mirrors regions.ts — exactly 89» ловит расхождение по count, но не по именам —
 * сверять имена вручную при изменениях).
 */
final class RussianRegions
{
    /** @var array<int, string> code(1..89) => официальное имя субъекта */
    public const CODE_TO_NAME = [
        // 24 республики
        1 => 'Республика Адыгея',
        2 => 'Республика Алтай',
        3 => 'Республика Башкортостан',
        4 => 'Республика Бурятия',
        5 => 'Республика Дагестан',
        6 => 'Донецкая Народная Республика',
        7 => 'Республика Ингушетия',
        8 => 'Кабардино-Балкарская Республика',
        9 => 'Республика Калмыкия',
        10 => 'Карачаево-Черкесская Республика',
        11 => 'Республика Карелия',
        12 => 'Республика Коми',
        13 => 'Республика Крым',
        14 => 'Луганская Народная Республика',
        15 => 'Республика Марий Эл',
        16 => 'Республика Мордовия',
        17 => 'Республика Саха (Якутия)',
        18 => 'Республика Северная Осетия — Алания',
        19 => 'Республика Татарстан',
        20 => 'Республика Тыва',
        21 => 'Удмуртская Республика',
        22 => 'Республика Хакасия',
        23 => 'Чеченская Республика',
        24 => 'Чувашская Республика',
        // 9 краёв
        25 => 'Алтайский край',
        26 => 'Забайкальский край',
        27 => 'Камчатский край',
        28 => 'Краснодарский край',
        29 => 'Красноярский край',
        30 => 'Пермский край',
        31 => 'Приморский край',
        32 => 'Ставропольский край',
        33 => 'Хабаровский край',
        // 48 областей
        34 => 'Амурская область',
        35 => 'Архангельская область',
        36 => 'Астраханская область',
        37 => 'Белгородская область',
        38 => 'Брянская область',
        39 => 'Владимирская область',
        40 => 'Волгоградская область',
        41 => 'Вологодская область',
        42 => 'Воронежская область',
        43 => 'Запорожская область',
        44 => 'Ивановская область',
        45 => 'Иркутская область',
        46 => 'Калининградская область',
        47 => 'Калужская область',
        48 => 'Кемеровская область',
        49 => 'Кировская область',
        50 => 'Костромская область',
        51 => 'Курганская область',
        52 => 'Курская область',
        53 => 'Ленинградская область',
        54 => 'Липецкая область',
        55 => 'Магаданская область',
        56 => 'Московская область',
        57 => 'Мурманская область',
        58 => 'Нижегородская область',
        59 => 'Новгородская область',
        60 => 'Новосибирская область',
        61 => 'Омская область',
        62 => 'Оренбургская область',
        63 => 'Орловская область',
        64 => 'Пензенская область',
        65 => 'Псковская область',
        66 => 'Ростовская область',
        67 => 'Рязанская область',
        68 => 'Самарская область',
        69 => 'Саратовская область',
        70 => 'Сахалинская область',
        71 => 'Свердловская область',
        72 => 'Смоленская область',
        73 => 'Тамбовская область',
        74 => 'Тверская область',
        75 => 'Томская область',
        76 => 'Тульская область',
        77 => 'Тюменская область',
        78 => 'Ульяновская область',
        79 => 'Херсонская область',
        80 => 'Челябинская область',
        81 => 'Ярославская область',
        // 3 города федерального значения
        82 => 'Москва',
        83 => 'Санкт-Петербург',
        84 => 'Севастополь',
        // 1 автономная область
        85 => 'Еврейская автономная область',
        // 4 автономных округа
        86 => 'Ненецкий автономный округ',
        87 => 'Ханты-Мансийский автономный округ — Югра',
        88 => 'Чукотский автономный округ',
        89 => 'Ямало-Ненецкий автономный округ',
    ];

    /**
     * Алиасы нестандартных форм реестра Россвязи → каноничное имя субъекта.
     * Города фед. значения приходят с префиксом «г. »; «Республика Удмуртская» —
     * перевёрнутый порядок слов; «Кемеровская область - Кузбасс обл.» — спец-форма.
     *
     * @var array<string, string>
     */
    private const REGION_ALIASES = [
        'г. Москва' => 'Москва',
        'Город Москва' => 'Москва',
        'г. Санкт-Петербург' => 'Санкт-Петербург',
        'г. Санкт - Петербург' => 'Санкт-Петербург',
        'г. Севастополь' => 'Севастополь',
        'Республика Саха /Якутия/' => 'Республика Саха (Якутия)',
        'Чувашская Республика - Чувашия' => 'Чувашская Республика',
        'Кемеровская область - Кузбасс обл.' => 'Кемеровская область',
        'Кемеровская область - Кузбасс область' => 'Кемеровская область',
        'Кемеровская область - Кузбасс' => 'Кемеровская область',
    ];

    /** @return array<string, int> name => code (обратный индекс) */
    public static function nameToCode(): array
    {
        return array_flip(self::CODE_TO_NAME);
    }

    /**
     * Нормализует строку региона реестра Россвязи в каноничное имя субъекта (или null).
     *
     * Реестр кодирует субъект как ПОСЛЕДНИЙ сегмент после «|»
     * (напр. «г. Воскресенск|р-н Воскресенский|Московская обл.» → «Московская обл.»),
     * с сокращением «обл.» вместо «область» и рядом нестандартных форм (см. REGION_ALIASES).
     * Безнадёжные/неоднозначные строки («-», «Российская Федерация»,
     * «Москва и Московская область», «г.о. Тольятти») → null.
     */
    public static function canonicalRegionName(string $raw): ?string
    {
        $segment = self::lastRegionSegment($raw);
        if ($segment === '') {
            return null;
        }

        // ХМАО приходит в множестве форм (em-dash/дефис, «Югра», « АО», капитализация) —
        // ловим по двум устойчивым маркерам до общих правил.
        if (mb_stripos($segment, 'Ханты') !== false && mb_stripos($segment, 'Мансийск') !== false) {
            return 'Ханты-Мансийский автономный округ — Югра';
        }

        if (isset(self::REGION_ALIASES[$segment])) {
            return self::REGION_ALIASES[$segment];
        }

        // «обл.» → «область»; « АО» → « автономный округ».
        $name = (string) preg_replace('/\s*обл\.$/u', ' область', $segment);
        $name = (string) preg_replace('/\s+АО$/u', ' автономный округ', $name);
        // Дефис с пробелами → длинное тире (эталон: «Республика Северная Осетия — Алания»).
        // Безопасно: ни одно каноническое имя не содержит дефис, окружённый пробелами
        // (составные имена вроде «Кабардино-Балкарская» используют дефис без пробелов).
        $name = str_replace(' - ', ' — ', $name);

        if (isset(self::nameToCode()[$name])) {
            return $name;
        }

        // Перевёрнутый порядок «Республика X» → «X Республика» (Удмуртская/Чеченская/
        // Чувашская/Кабардино-Балкарская/Карачаево-Черкесская, Донецкая Народная/
        // Луганская Народная). Республика-first каноны (Татарстан, Карелия…) уже
        // отловлены прямым попаданием выше.
        if (preg_match('/^Республика\s+(.+)$/u', $name, $m) === 1) {
            $reordered = trim($m[1]).' Республика';
            if (isset(self::nameToCode()[$reordered])) {
                return $reordered;
            }
        }

        return null;
    }

    /** Резолвит строку региона реестра Россвязи в subject_code (1..89) или null. */
    public static function resolveSubjectCode(string $raw): ?int
    {
        $name = self::canonicalRegionName($raw);

        return $name === null ? null : (self::nameToCode()[$name] ?? null);
    }

    /** Последний сегмент после «|» (субъект в формате Россвязи), trimmed. */
    private static function lastRegionSegment(string $raw): string
    {
        $parts = explode('|', $raw);

        return trim((string) end($parts));
    }
}
