from __future__ import annotations

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


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

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 una URL PostgreSQL valida")
        return SecretStr(url)


class KeycloakConfig(BaseModel):
    server_url: AnyUrl
    realm: str
    client_id: str
    client_secret: SecretStr

    model_config = ConfigDict(extra="forbid")

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

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")

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")

    @field_validator("username")
    @classmethod
    def validate_username(cls, value: str) -> str:
        value = value.strip()
        if not value:
            raise ValueError("pagopa.username vuoto")
        return value

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

    model_config = ConfigDict(extra="forbid")


class PathsConfig(BaseModel):
    upload_dir: str
    template_dir: str

    model_config = ConfigDict(extra="forbid")

    @field_validator("upload_dir", "template_dir")
    @classmethod
    def validate_paths(cls, value: str) -> str:
        value = value.strip()
        if not value:
            raise ValueError("path vuoto")
        return value

#### impostazioni OIDC del tenant, solo quello che varia..... 
class OidcTenantSettings(BaseModel):
    realm: str
    redirect_uri: AnyUrl
    public_base_url: AnyUrl | None = None


class TenantConfig(BaseModel):
    tenant: str
    comune: ComuneConfig

    db: DbConfig | None = None
    pagopa: PagopaConfig | None = None
    email: EmailConfig | None = None
    protocollo: ProtocolloConfig | None = None

    keycloak_admin: KeycloakConfig | None = None
    bff_oidc: OidcTenantSettings | None = None

    paths: PathsConfig | None = None
    model_config = ConfigDict(extra="forbid")

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


### settings delle app condivisi per il multitenant 
class OidcSharedSettings(BaseModel):
    oidc_base_url: str
    client_id: str
    scope: str = "openid email profile"
    auth_method: str = "private_key_jwt"
    public_base_url: str



    
##### configurazione completa per client oidc
class OidcBffConfig(BaseModel):
    realm: str
    issuer: AnyUrl

    authorization_endpoint: AnyUrl
    revocation_endpoint: AnyUrl | None = None
    end_session_endpoint: AnyUrl | None = None

    token_endpoint: AnyUrl
    jwks_uri: AnyUrl | None = None

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

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

    kid: str | None = None

    model_config = ConfigDict(extra="forbid")
    
##### configurazione completa per client oidc come sopra rinominata... ma penso non serva poù
class ResolvedOidcConfig_XXX(BaseModel):
    realm: str
    issuer: AnyUrl
    authorization_endpoint: AnyUrl
    token_endpoint: AnyUrl
    revocation_endpoint: AnyUrl | None = None
    end_session_endpoint: AnyUrl | None = None
    jwks_uri: AnyUrl | None = None
    client_id: str
    redirect_uri: AnyUrl
    post_logout_redirect_uri: AnyUrl | None = None
    scope: str = "openid email profile"
    token_endpoint_auth_method: str = "private_key_jwt"