"""État de configuration de la GUI V6 (G3-B), testable sans display ni fichiers.

Détient les options simples exposées par l'onglet Configuration et sait produire
des :class:`EngineSettings`. La résolution des profils s'appuie sur
``profile_defaults`` (jamais modifié) avec injection possible pour les tests.
"""

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path
from typing import Callable, FrozenSet, List, Optional

from gui_v6.engine_bridge import EngineSettings

# Mapping centralisé champ ConfigState → CATÉGORIE moteur (Plan 1b / P1-2).
#
# Les 7 catégories doivent matcher EXACTEMENT le set accepté par
# ``anonymizer_core_refactored_onnx.process_pdf(disabled_kinds=...)`` :
#   {"NOM", "DATE_NAISSANCE", "ETAB", "ADRESSE", "NIR", "TEL", "ADHERENT"}.
#
# Sémantique des booléens ``detect_*`` : True = « détecter cette catégorie »
# (= masquer, comportement par défaut). False = laisser en clair → la catégorie
# entre dans ``disabled_kinds``. Note : CODE_POSTAL suit le toggle ADRESSE côté
# moteur (décision Dom 2026-06-26), aucun toggle dédié n'est exposé.
#
# L'ordre suit les 7 lignes de ``tab_config._DETECTION_OPTIONS`` :
#   Noms/prénoms · Dates de naissance · Établissements · Adresses/CP ·
#   N° sécurité sociale · Téléphones · N° adhérent mutuelle.
CATEGORY_FIELDS = {
    "detect_nom": "NOM",
    "detect_date_naissance": "DATE_NAISSANCE",
    "detect_etab": "ETAB",
    "detect_adresse": "ADRESSE",
    "detect_nir": "NIR",
    "detect_tel": "TEL",
    "detect_adherent": "ADHERENT",
}
# Catégories canoniques (ordre = ordre des toggles UI).
DETECTION_CATEGORIES = tuple(CATEGORY_FIELDS.values())


@dataclass
class ConfigState:
    """Options de configuration utilisateur (réglages simples G3-B)."""

    profile: Optional[str] = None
    raster_burn: bool = True
    use_local_ner: bool = True
    enable_eds: bool = False
    enable_gliner: bool = False
    output_dir: Optional[Path] = None
    ogc_label: Optional[str] = None
    manual_mask_required: bool = False
    manual_mask_template: Optional[Path] = None
    mask_color: str = "#000000"
    mask_marker_style: str = "brackets"
    mask_margin_x: int = 2
    mask_margin_y: int = 1
    mask_rounded_corners: bool = False

    # 7 toggles « Données à détecter » — tous ON par défaut (zéro changement).
    detect_nom: bool = True
    detect_date_naissance: bool = True
    detect_etab: bool = True
    detect_adresse: bool = True
    detect_nir: bool = True
    detect_tel: bool = True
    detect_adherent: bool = True

    def disabled_kinds(self) -> FrozenSet[str]:
        """Set des CATÉGORIES décochées (laissées en clair).

        Défaut (tous les toggles ON) ⇒ ``frozenset()`` (no-op moteur).
        """
        return frozenset(
            category
            for field_name, category in CATEGORY_FIELDS.items()
            if not getattr(self, field_name)
        )

    def to_engine_settings(self, config_path: Optional[Path] = None) -> EngineSettings:
        return EngineSettings(
            make_vector_redaction=False,
            also_make_raster_burn=self.raster_burn,
            config_path=config_path,
            use_local_ner=self.use_local_ner,
            enable_eds=self.enable_eds,
            enable_gliner=self.enable_gliner,
            ogc_label=self.ogc_label,
            profile=self.profile,
            disabled_kinds=self.disabled_kinds(),
        )


def list_profile_keys(lister: Optional[Callable[[], dict]] = None) -> List[str]:
    """Liste triée des clés de profils. Best-effort : [] si indisponible."""
    if lister is None:
        from profile_defaults import list_effective_profiles

        lister = list_effective_profiles
    try:
        return sorted(lister().keys())
    except Exception:
        return []


def default_profile_key(getter: Optional[Callable[[], str]] = None) -> Optional[str]:
    """Clé du profil par défaut, ou None si indisponible."""
    if getter is None:
        from profile_defaults import get_default_profile_key

        getter = get_default_profile_key
    try:
        return getter()
    except Exception:
        return None
