from __future__ import annotations

from pydantic import AnyUrl, BaseModel, ConfigDict, SecretStr, field_validator


# =========================================================
# METADATA
# =========================================================

class ComuneConfig(BaseModel):
    nome: str

    model_config = ConfigDict(extra="forbid")

    @field_validator("nome")
    @classmethod
    def validate_nome(cls, value: str) -> str:
        value = value.strip()
        if not value:
            raise ValueError("comune.nome vuoto")
        return value


# =========================================================
# DATABASE (sempre tenant-specific)
# =========================================================

class DbConfig(BaseModel):
    url: SecretStr

    model_config = ConfigDict(extra="forbid")

    @field_validator("url")
    @classmethod
    def validate_url(cls, value: SecretStr) -> SecretStr:
        url = value.get_secret_value().strip()
        if not url.startswith("postgresql"):
            raise ValueError("db.url deve essere PostgreSQL")
        return SecretStr(url)


# =========================================================
# OIDC (tenant override + shared + resolved)
# =========================================================

class OidcSharedSettings(BaseModel):
    base_url: str
    client_id: str
    scope: str = "openid email profile"
    auth_method: str = "private_key_jwt"
    public_base_url: str
    redirect_path: str = "/api/auth/callback"

    model_config = ConfigDict(extra="forbid")

    @field_validator(
        "base_url",
        "client_id",
        "scope",
        "auth_method",
        "public_base_url",
        "redirect_path",
    )
    @classmethod
    def validate_non_empty(cls, value: str) -> str:
        value = value.strip()
        if not value:
            raise ValueError("campo OIDC shared vuoto")
        return value


class OidcTenantOverride(BaseModel):
    realm: str
    client_id: str | None = None
    public_base_url: str | None = None
    redirect_path: str | None = None
    scope: str | None = None
    auth_method: str | None = None

    model_config = ConfigDict(extra="forbid")

    @field_validator("realm")
    @classmethod
    def validate_realm(cls, value: str) -> str:
        value = value.strip()
        if not value:
            raise ValueError("bff_oidc.realm vuoto")
        return value

    @field_validator(
        "client_id",
        "public_base_url",
        "redirect_path",
        "scope",
        "auth_method",
    )
    @classmethod
    def strip_optional_strings(cls, value: str | None) -> str | None:
        if value is None:
            return None
        value = value.strip()
        return value or None


class OidcBffConfig(BaseModel):
    realm: str
    issuer: str
    authorization_endpoint: str
    token_endpoint: str
    revocation_endpoint: str | None = None
    end_session_endpoint: str | None = None
    jwks_uri: str | None = None

    client_id: str
    redirect_uri: str
    post_logout_redirect_uri: str | None = None

    scope: str = "openid email profile"
    token_endpoint_auth_method: str = "private_key_jwt"

    model_config = ConfigDict(extra="forbid")


# =========================================================
# EMAIL (override + resolved)
# =========================================================

class EmailTenantOverride(BaseModel):
    smtp_host: str | None = None
    smtp_port: int | None = None
    username: str | None = None
    password: SecretStr | None = None
    use_tls: bool | None = None
    from_address: str | None = None

    model_config = ConfigDict(extra="forbid")


class EmailConfig(BaseModel):
    smtp_host: str
    smtp_port: int = 587
    username: str
    password: SecretStr
    use_tls: bool = True
    from_address: str | None = None

    model_config = ConfigDict(extra="forbid")


# =========================================================
# PAGOPA (override + resolved)
# =========================================================

class PagopaTenantOverride(BaseModel):
    username: str | None = None
    password: SecretStr | None = None
    print_username: str | None = None
    print_password: SecretStr | None = None
    service_url: AnyUrl | None = None
    codipa: str | None = None

    model_config = ConfigDict(extra="forbid")


class PagopaConfig(BaseModel):
    username: str
    password: SecretStr
    print_username: str
    print_password: SecretStr
    service_url: AnyUrl | None = None
    codipa: str | None = None

    model_config = ConfigDict(extra="forbid")


# =========================================================
# PROTOCOLLO (override + resolved)
# =========================================================

class ProtocolloTenantOverride(BaseModel):
    base_url: AnyUrl | None = None
    username: str | None = None
    password: SecretStr | None = None

    model_config = ConfigDict(extra="forbid")


class ProtocolloConfig(BaseModel):
    base_url: AnyUrl
    username: str
    password: SecretStr

    model_config = ConfigDict(extra="forbid")


# =========================================================
# TENANT CONFIG (sorgente)
# =========================================================

class TenantConfig(BaseModel):
    name: str | None = None

    comune: ComuneConfig | None = None

    db: DbConfig

    oidc: OidcTenantOverride

    pagopa: PagopaTenantOverride | None = None
    email: EmailTenantOverride | None = None
    protocollo: ProtocolloTenantOverride | None = None

    model_config = ConfigDict(extra="forbid")
