from __future__ import annotations

from functools import lru_cache
from pathlib import Path

from pydantic import Field, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
from sqlalchemy.engine import URL


class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        extra="ignore",
        case_sensitive=False,
    )

    # Application / serveur
    app_name: str = "Portail Frelons AULA TernoisCom"
    app_env: str = "development"
    app_base_url: str = "http://127.0.0.1:8000"
    public_portal_title: str = "Portail frelons asiatiques"
    app_host: str = "127.0.0.1"
    app_port: int = 8000
    uvicorn_workers: int = 1
    forwarded_allow_ips: str = "127.0.0.1"
    docs_enabled: bool = True
    auto_create_tables: bool = False

    # Sécurité HTTP
    trusted_hosts: list[str] | str = ["127.0.0.1", "localhost"]
    force_https: bool = False
    cors_origins: list[str] | str = [
        "http://localhost:8000",
        "http://127.0.0.1:8000",
    ]

    # Authentification applicative PostgreSQL
    admin_auth_enabled: bool = True  # compatibilite avec les anciens fichiers .env
    session_secret_key: str = ""
    session_cookie_name: str = "frelons_session"
    session_cookie_secure: bool = False
    session_max_age_seconds: int = 28_800

    # PostgreSQL / PostGIS
    pghost: str = "127.0.0.1"
    pgport: int = 5432
    pgdatabase: str = "ternois"
    pguser: str = ""
    pgpassword: str = ""
    pgsslmode: str = "disable"
    db_pool_size: int = 5
    db_max_overflow: int = 5
    db_pool_recycle_seconds: int = 1_800

    # Compatibilité facultative avec l'ancien fichier .env.
    database_url_override: str | None = Field(
        default=None,
        validation_alias="DATABASE_URL",
        exclude=True,
    )

    # Chemins relatifs au dossier du projet
    data_dir: str = "data"
    communes_geojson: str = "communes_ternois.geojson"
    backup_dir: str = "backups"

    # Fichiers / photos
    upload_dir: str = "uploads"
    max_upload_mb: int = 12
    image_max_width: int = 2_560
    image_max_height: int = 2_560
    image_jpeg_quality: int = 86

    # Journaux
    log_dir: str = "logs"
    log_level: str = "INFO"
    log_max_bytes: int = 10_485_760
    log_backup_count: int = 10

    # Cartographie
    geocoding_url: str = "https://data.geopf.fr/geocodage/search"

    # Assistance
    support_email: str = "frelons@ternoiscom.fr"
    support_phone: str = ""

    # Courriels
    notifications_enabled: bool = False
    smtp_host: str | None = None
    smtp_port: int = 587
    smtp_user: str | None = None
    smtp_password: str | None = None
    smtp_from: str = "frelons@ternoiscom.fr"
    smtp_use_tls: bool = True
    smtp_use_ssl: bool = False
    notification_recipients: list[str] | str = [
        "frelon@ternoiscom.fr",
        "contact@ternoiscom.fr",
    ]

    @field_validator("cors_origins", "notification_recipients", "trusted_hosts", mode="before")
    @classmethod
    def split_csv(cls, value):
        if isinstance(value, str):
            return [item.strip() for item in value.split(",") if item.strip()]
        return value

    @field_validator("app_env", mode="before")
    @classmethod
    def normalise_environment(cls, value):
        return str(value or "development").strip().lower()

    @field_validator("log_level", mode="before")
    @classmethod
    def normalise_log_level(cls, value):
        return str(value or "INFO").strip().upper()

    @property
    def is_production(self) -> bool:
        return self.app_env == "production"

    @property
    def database_url(self) -> str | URL:
        """Construit la connexion SQLAlchemy depuis les variables PG*."""
        if self.database_url_override:
            return self.database_url_override

        query: dict[str, str] = {}
        if self.pgsslmode:
            query["ssl"] = self.pgsslmode

        return URL.create(
            drivername="postgresql+asyncpg",
            username=self.pguser or None,
            password=self.pgpassword or None,
            host=self.pghost or None,
            port=self.pgport,
            database=self.pgdatabase or None,
            query=query,
        )

    @property
    def project_root(self) -> Path:
        return Path(__file__).resolve().parents[2]

    @property
    def upload_path(self) -> Path:
        path = Path(self.upload_dir)
        return path.resolve() if path.is_absolute() else (self.project_root / path).resolve()

    @property
    def log_path(self) -> Path:
        path = Path(self.log_dir)
        return path.resolve() if path.is_absolute() else (self.project_root / path).resolve()

    @property
    def data_path(self) -> Path:
        path = Path(self.data_dir)
        return path.resolve() if path.is_absolute() else (self.project_root / path).resolve()

    @property
    def communes_geojson_path(self) -> Path:
        path = Path(self.communes_geojson)
        return path.resolve() if path.is_absolute() else (self.data_path / path).resolve()

    @property
    def backup_path(self) -> Path:
        path = Path(self.backup_dir)
        return path.resolve() if path.is_absolute() else (self.project_root / path).resolve()

    def validate_production(self) -> list[str]:
        errors: list[str] = []
        if not self.is_production:
            return errors
        if len(self.session_secret_key) < 32:
            errors.append("SESSION_SECRET_KEY doit contenir au moins 32 caractères.")
        if self.docs_enabled:
            errors.append("DOCS_ENABLED doit être false en production, sauf besoin explicite.")
        if "*" in self.trusted_hosts:
            errors.append("TRUSTED_HOSTS ne doit pas contenir * en production.")
        if not self.pguser or not self.pgdatabase or not self.pghost:
            errors.append("Les paramètres PostgreSQL sont incomplets.")
        if self.session_cookie_secure and not self.app_base_url.lower().startswith("https://"):
            errors.append("APP_BASE_URL doit commencer par https:// lorsque SESSION_COOKIE_SECURE=true.")
        return errors

    def database_summary(self) -> dict[str, str | int]:
        """Retourne uniquement les informations non sensibles de connexion."""
        if self.database_url_override:
            try:
                from sqlalchemy.engine import make_url

                url = make_url(self.database_url_override)
            except Exception:
                return {"serveur": "URL invalide", "port": 0, "base": "", "utilisateur": "", "ssl": ""}
            return {
                "serveur": url.host or "",
                "port": url.port or 5432,
                "base": url.database or "",
                "utilisateur": url.username or "",
                "ssl": str(url.query.get("ssl", "")),
            }

        return {
            "serveur": self.pghost,
            "port": self.pgport,
            "base": self.pgdatabase,
            "utilisateur": self.pguser,
            "ssl": self.pgsslmode,
        }


@lru_cache
def get_settings() -> Settings:
    return Settings()
