from pathlib import Path
import yaml
from .models import TenantConfig

from .models import (
    OidcBffConfig,
    EmailConfig,
    PagopaConfig,
    ProtocolloConfig,
)
from .resolvers import (
    resolve_oidc_config,
    resolve_email_config,
    resolve_pagopa_config,
    resolve_protocollo_config,
)

class TenantConfigService:
    def __init__(self, secret_file: str):
        self.secret_file = Path(secret_file)
        self._cache: dict[str, TenantConfig] = {}
        self._loaded = False

    def _load_all(self) -> None:
        if not self.secret_file.exists():
            raise FileNotFoundError(
                f"Tenant config file '{self.secret_file}' non trovato"
            )

        data = yaml.safe_load(self.secret_file.read_text(encoding="utf-8")) or {}

        if not isinstance(data, dict):
            raise ValueError("Il file tenants.yml deve contenere una mappa tenant -> config")

        loaded: dict[str, TenantConfig] = {}

        for tenant, cfg in data.items():
            if not isinstance(tenant, str) or not tenant.strip():
                raise ValueError("Chiave tenant non valida nel file tenants.yml")

            tenant_key = tenant.strip().lower()

            if not isinstance(cfg, dict):
                raise ValueError(f"La configurazione del tenant '{tenant_key}' deve essere un oggetto")

            # opzionale: name derivato dal nome chiave
            cfg.setdefault("name", tenant_key)

            loaded[tenant_key] = TenantConfig(**cfg)

        self._cache = loaded
        self._loaded = True

    def get(self, tenant: str) -> TenantConfig:
        tenant = tenant.strip().lower()

        if not self._loaded:
            self._load_all()

        try:
            return self._cache[tenant]
        except KeyError as exc:
            raise FileNotFoundError(f"Tenant config '{tenant}' non trovato") from exc

    def list_tenants(self) -> list[str]:
        if not self._loaded:
            self._load_all()
        return sorted(self._cache.keys())

    # def invalidate(self):
    #     self._cache.clear()
    #     self._loaded = False




class TenantRuntimeConfigService:
    def __init__(self, tenant_service, settings):
        self.tenant_service = tenant_service
        self.settings = settings

        self._oidc_cache: dict[str, OidcBffConfig] = {}
        self._email_cache: dict[str, EmailConfig] = {}
        self._pagopa_cache: dict[str, PagopaConfig] = {}
        self._protocollo_cache: dict[str, ProtocolloConfig] = {}

    # -------------------------
    # OIDC
    # -------------------------

    def get_oidc(self, tenant: str) -> OidcBffConfig:
        if tenant not in self._oidc_cache:
            tenant_cfg = self.tenant_service.get(tenant)
            self._oidc_cache[tenant] = OidcBffConfig(
                **resolve_oidc_config(tenant_cfg, self.settings)
            )
        return self._oidc_cache[tenant]

    # -------------------------
    # EMAIL
    # -------------------------

    def get_email(self, tenant: str) -> EmailConfig:
        if tenant not in self._email_cache:
            tenant_cfg = self.tenant_service.get(tenant)
            self._email_cache[tenant] = EmailConfig(
                **resolve_email_config(tenant_cfg, self.settings)
            )
        return self._email_cache[tenant]

    # -------------------------
    # PAGOPA
    # -------------------------

    def get_pagopa(self, tenant: str) -> PagopaConfig:
        if tenant not in self._pagopa_cache:
            tenant_cfg = self.tenant_service.get(tenant)
            self._pagopa_cache[tenant] = PagopaConfig(
                **resolve_pagopa_config(tenant_cfg, self.settings)
            )
        return self._pagopa_cache[tenant]

    # -------------------------
    # PROTOCOLLO
    # -------------------------

    def get_protocollo(self, tenant: str) -> ProtocolloConfig:
        if tenant not in self._protocollo_cache:
            tenant_cfg = self.tenant_service.get(tenant)
            self._protocollo_cache[tenant] = ProtocolloConfig(
                **resolve_protocollo_config(tenant_cfg, self.settings)
            )
        return self._protocollo_cache[tenant]

    # -------------------------
    # INVALIDATE
    # -------------------------

    def invalidate(self, tenant: str | None = None):
        caches = [
            self._oidc_cache,
            self._email_cache,
            self._pagopa_cache,
            self._protocollo_cache,
        ]

        if tenant is None:
            for cache in caches:
                cache.clear()
        else:
            for cache in caches:
                cache.pop(tenant, None)