<?php

declare(strict_types=1);

namespace App\Support;

use Illuminate\Support\Facades\Log;

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

    /**
     * Переводит Лидерра-коды регионов в коды поставщика. Неизвестные (нет у
     * поставщика) отбрасываются с warning'ом; sentinel 0 («Вся РФ») игнорируется.
     * Результат — уникальные коды поставщика по возрастанию.
     *
     * @param  list<int>|array<int|string, int|string>  $liderraCodes
     * @return list<int>
     */
    public static function mapToSupplier(array $liderraCodes): array
    {
        $out = [];
        $dropped = [];

        foreach ($liderraCodes as $code) {
            $code = (int) $code;
            if ($code === 0) {
                continue; // sentinel «Вся РФ»
            }
            if (isset(self::LIDERRA_TO_SUPPLIER[$code])) {
                $out[self::LIDERRA_TO_SUPPLIER[$code]] = true;
            } else {
                $dropped[] = $code;
            }
        }

        if ($dropped !== []) {
            Log::warning('supplier.regions.unmapped', [
                'liderra_codes' => $dropped,
                'note' => 'supplier does not offer these subjects — geo-filter dropped for them',
            ]);
        }

        $codes = array_keys($out);
        sort($codes);

        return $codes;
    }

    /**
     * Инверсия {@see mapToSupplier}: коды поставщика (ГИБДД) → Лидерра-коды
     * (конституционный порядок). Неизвестные коды поставщика отбрасываются
     * с warning'ом. Результат — уникальные Лидерра-коды по возрастанию.
     *
     * @param  list<int>|array<int|string, int|string>  $supplierCodes
     * @return list<int>
     */
    public static function mapFromSupplier(array $supplierCodes): array
    {
        /** @var array<int, int> $supplierToLiderra */
        $supplierToLiderra = array_flip(self::LIDERRA_TO_SUPPLIER);

        $out = [];
        $dropped = [];

        foreach ($supplierCodes as $code) {
            $code = (int) $code;
            if (isset($supplierToLiderra[$code])) {
                $out[$supplierToLiderra[$code]] = true;
            } else {
                $dropped[] = $code;
            }
        }

        if ($dropped !== []) {
            Log::warning('supplier.regions.unmapped_reverse', [
                'supplier_codes' => $dropped,
                'note' => 'supplier code has no Liderra equivalent — dropped on import',
            ]);
        }

        $codes = array_keys($out);
        sort($codes);

        return $codes;
    }
}
