"""Загрузчик целевого справочника медицинских услуг.

Справочник (`Справочник услуг.xlsx`) — это эталон, к которому нормализуются все
извлечённые из прайсов позиции. Колонки исходного файла:

    ID | Специальность | Code | Name_ru | TarificatrCode

Синонимов в справочнике нет, поэтому автоматическое сопоставление опирается на
код тарификатора (точное совпадение) и на эмбеддинги названий. Этот модуль
отвечает только за загрузку и подготовку индексов; само сопоставление — в
`etl/normalize`.
"""

from __future__ import annotations

import re
from dataclasses import dataclass, field
from pathlib import Path

from openpyxl import load_workbook

# Код тарификатора в формате РК: буква + три группы цифр, например «A02.004.000».
TARIFICATOR_RE = re.compile(r"^[A-ZА-Я]\d{2}\.\d{3}\.\d{3}$")

_WHITESPACE_RE = re.compile(r"\s+")


def normalize_name(text: str | None) -> str:
    """Привести название услуги к форме для сравнения.

    Нижний регистр, унификация «ё»→«е», дефисы и кратные пробелы схлопываются в
    один пробел. Исходное написание при этом нигде не теряется — нормализованная
    форма используется только как ключ сопоставления.
    """
    s = (text or "").strip().lower().replace("ё", "е")
    s = s.replace("-", " ")
    return _WHITESPACE_RE.sub(" ", s).strip()


@dataclass
class Service:
    """Одна запись эталонного справочника услуг."""

    service_id: str  # стабильный идентификатор «<ID>-<Code>»
    specialty: str  # специальность — служит и категорией, и сужением поиска
    name_ru: str  # официальное название
    tarificator_code: str | None  # код тарификатора (если задан)
    name_norm: str = field(default="")  # нормализованная форма name_ru


def load_dictionary(path: str | Path) -> list[Service]:
    """Загрузить справочник из xlsx и вернуть список услуг с нормализованными именами.

    Заголовки ищутся по именам колонок, а не по позиции, — так загрузчик переживёт
    перестановку столбцов. Строки с пустым названием пропускаются.
    """
    workbook = load_workbook(path, read_only=True, data_only=True)
    sheet = workbook.active
    rows = sheet.iter_rows(values_only=True)

    header = [str(c).strip() if c is not None else "" for c in next(rows)]
    col = {name: header.index(name) for name in header if name}
    name_idx = col.get("Name_ru")
    if name_idx is None:
        raise ValueError(f"В справочнике нет колонки Name_ru. Заголовки: {header}")

    services: list[Service] = []
    seen_ids: dict[str, int] = {}
    for row in rows:
        raw_name = row[name_idx]
        if not raw_name or not str(raw_name).strip():
            continue

        tar_raw = row[col["TarificatrCode"]] if "TarificatrCode" in col else None
        tar = str(tar_raw).strip() if tar_raw else None
        if tar and not TARIFICATOR_RE.match(tar):
            tar = None  # отбрасываем мусорные коды, оставляем только валидный формат

        # «<ID>-<Code>» иногда повторяется в справочнике — гарантируем уникальность.
        sid = f"{row[col['ID']]}-{row[col['Code']]}"
        repeat = seen_ids.get(sid, 0)
        seen_ids[sid] = repeat + 1
        if repeat:
            sid = f"{sid}#{repeat}"

        service = Service(
            service_id=sid,
            specialty=str(row[col["Специальность"]]).strip() if row[col["Специальность"]] else "",
            name_ru=str(raw_name).strip(),
            tarificator_code=tar,
        )
        service.name_norm = normalize_name(service.name_ru)
        services.append(service)

    return services
