"""Configuration du pipeline — Pydantic BaseSettings + chargement niches.yaml."""

from __future__ import annotations

from functools import lru_cache
from pathlib import Path
from typing import Any

import yaml
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict

PROJECT_ROOT = Path(__file__).resolve().parent.parent
CONFIG_DIR = PROJECT_ROOT / "config"
DATA_DIR = PROJECT_ROOT / "data"


class Settings(BaseSettings):
    """Variables d'environnement requises par le pipeline."""

    model_config = SettingsConfigDict(
        env_file=PROJECT_ROOT / ".env",
        env_file_encoding="utf-8",
        case_sensitive=False,
        extra="ignore",
    )

    firecrawl_api_key: str = Field(description="Clé API Firecrawl")
    firecrawl_base_url: str = Field(
        default="https://crawl.elevaseo.app",
        description="URL de base Firecrawl",
    )
    baserow_token: str = Field(description="Token Baserow")
    baserow_table_id: int = Field(description="ID de la table Baserow Leads")
    baserow_base_url: str = Field(
        default="http://localhost",
        description="URL de base Baserow",
    )
    pagespeed_api_key: str = Field(
        default="",
        description="Clé API PageSpeed Insights (optionnel)",
    )
    anthropic_api_key: str = Field(description="Clé API Anthropic pour l'extraction LLM")
    baserow_email: str = Field(default="", description="Email admin Baserow (pour init options)")
    baserow_password: str = Field(default="", description="Password admin Baserow (pour init options)")
    reacher_url: str = Field(default="", description="URL Reacher distant (ex: https://reacher.elevaseo.app)")
    reacher_secret: str = Field(default="", description="Secret Reacher distant (header x-reacher-secret)")
    reacher_from_email: str = Field(default="", description="From email Reacher distant (SMTP MAIL FROM)")
    reacher_url_local: str = Field(default="http://localhost:8080", description="URL Reacher local (Docker)")
    reacher_secret_local: str = Field(default="", description="Secret Reacher local")
    reacher_from_email_local: str = Field(default="", description="From email Reacher local")
    espocrm_url: str = Field(default="", description="URL de base EspoCRM (ex: https://espo.elevaseo.app)")
    espocrm_api_key: str = Field(default="", description="Clé API EspoCRM (X-Api-Key)")
    resend_api_key: str = Field(default="", description="Clé API Resend (pour sync bounces)")


class LLMConfig:
    """Configuration LLM + rate limits depuis llm.yaml."""

    def __init__(self, data: dict[str, Any]) -> None:
        self._data = data

    @property
    def extraction_model(self) -> str:
        return str(self._data["extraction"]["model"])

    @property
    def extraction_max_tokens(self) -> int:
        return int(self._data["extraction"]["max_tokens"])

    @property
    def extraction_max_input_chars(self) -> int:
        return int(self._data["extraction"]["max_input_chars"])

    def rate_limit(self, service: str) -> dict[str, int]:
        """Retourne la config rate limit pour un service (pagespeed, anthropic)."""
        return dict(self._data.get("rate_limits", {}).get(service, {}))


class NichesConfig:
    """Configuration des niches, régions et scoring depuis niches.yaml."""

    def __init__(self, data: dict[str, Any]) -> None:
        self._data = data

    @property
    def scoring_threshold(self) -> int:
        return int(self._data["scoring"]["threshold"])

    @property
    def scoring_weights(self) -> dict[str, int]:
        return dict(self._data["scoring"]["weights"])

    @property
    def niches(self) -> dict[str, dict[str, Any]]:
        return dict(self._data["niches"])

    @property
    def regions(self) -> list[str]:
        return list(self._data["regions"])

    def get_queries(self, niche: str) -> list[str]:
        """Retourne les queries pour une niche donnée."""
        niche_data = self.niches.get(niche)
        if niche_data is None:
            raise ValueError(f"Niche inconnue : {niche!r}. Disponibles : {list(self.niches.keys())}")
        return list(niche_data["queries"])


@lru_cache
def get_settings() -> Settings:
    """Singleton Settings — chargé une seule fois."""
    return Settings()  # type: ignore[call-arg]


def get_reacher_config(local: bool = False) -> dict[str, str]:
    """Retourne url/secret/from_email Reacher selon le mode (local ou distant)."""
    s = get_settings()
    if local:
        return {
            "url": s.reacher_url_local,
            "secret": s.reacher_secret_local,
            "from_email": s.reacher_from_email_local,
        }
    return {
        "url": s.reacher_url,
        "secret": s.reacher_secret,
        "from_email": s.reacher_from_email,
    }


@lru_cache
def get_llm_config(path: Path = CONFIG_DIR / "llm.yaml") -> LLMConfig:
    """Charge et cache la config llm.yaml."""
    with open(path, encoding="utf-8") as f:
        data = yaml.safe_load(f)
    return LLMConfig(data)


@lru_cache
def get_excluded_domains(path: Path = CONFIG_DIR / "excluded_domains.txt") -> frozenset[str]:
    """Charge la liste des domaines exclus (un par ligne)."""
    if not path.exists():
        return frozenset()
    with open(path, encoding="utf-8") as f:
        return frozenset(
            line.strip().lower() for line in f if line.strip() and not line.startswith("#")
        )


@lru_cache
def get_niches_config(path: Path = CONFIG_DIR / "niches.yaml") -> NichesConfig:
    """Charge et cache la config niches.yaml."""
    with open(path, encoding="utf-8") as f:
        data = yaml.safe_load(f)
    return NichesConfig(data)
