from __future__ import annotations

from pathlib import Path

from pydantic import SecretStr

from .models import (
    EmailConfig,
    OidcBffConfig,
    OidcSharedSettings,
    PagopaConfig,
    ProtocolloConfig,
    TenantConfig,
)


def _read_secret_file(path: str | None) -> str | None:
    if not path:
        return None

    value = Path(path).read_text(encoding="utf-8").strip()
    return value or None


def _coalesce(*values):
    for value in values:
        if value is not None:
            return value
    return None


def resolve_oidc_config(
    tenant_cfg: TenantConfig,
    shared: OidcSharedSettings,
) -> OidcBffConfig:
    tenant_oidc = tenant_cfg.bff_oidc

    realm = tenant_oidc.realm
    client_id = _coalesce(tenant_oidc.client_id, shared.client_id)
    public_base_url = _coalesce(
        tenant_oidc.public_base_url,
        shared.public_base_url,
    )
    redirect_path = _coalesce(
        tenant_oidc.redirect_path,
        shared.redirect_path,
    )
    scope = _coalesce(
        tenant_oidc.scope,
        shared.scope,
    )
    auth_method = _coalesce(
        tenant_oidc.auth_method,
        shared.auth_method,
    )

    base_url = shared.base_url.rstrip("/")
    issuer = f"{base_url}/realms/{realm}"

    redirect_uri = f"{public_base_url.rstrip('/')}{redirect_path}"
    post_logout_redirect_uri = public_base_url.rstrip("/")

    return OidcBffConfig(
        realm=realm,
        issuer=issuer,
        authorization_endpoint=f"{issuer}/protocol/openid-connect/auth",
        token_endpoint=f"{issuer}/protocol/openid-connect/token",
        revocation_endpoint=f"{issuer}/protocol/openid-connect/revoke",
        end_session_endpoint=f"{issuer}/protocol/openid-connect/logout",
        jwks_uri=f"{issuer}/protocol/openid-connect/certs",
        client_id=client_id,
        redirect_uri=redirect_uri,
        post_logout_redirect_uri=post_logout_redirect_uri,
        scope=scope,
        token_endpoint_auth_method=auth_method,
    )


def resolve_email_config(
    tenant_cfg: TenantConfig,
    settings,
) -> EmailConfig:
    tenant_email = tenant_cfg.email

    default_password: str | None = None
    if getattr(settings, "smtp_password", None):
        default_password = settings.smtp_password
    elif getattr(settings, "smtp_password_file", None):
        default_password = _read_secret_file(settings.smtp_password_file)

    tenant_password = (
        tenant_email.password.get_secret_value()
        if tenant_email and tenant_email.password
        else None
    )

    password = _coalesce(tenant_password, default_password)
    if password is None:
        raise ValueError(
            f"Configurazione email incompleta per tenant '{tenant_cfg.tenant}': "
            "password non disponibile"
        )

    return EmailConfig(
        smtp_host=_coalesce(
            tenant_email.smtp_host if tenant_email else None,
            settings.smtp_host,
        ),
        smtp_port=_coalesce(
            tenant_email.smtp_port if tenant_email else None,
            settings.smtp_port,
        ),
        username=_coalesce(
            tenant_email.username if tenant_email else None,
            settings.smtp_username,
        ),
        password=SecretStr(password),
        use_tls=_coalesce(
            tenant_email.use_tls if tenant_email else None,
            settings.smtp_use_tls,
        ),
        from_address=_coalesce(
            tenant_email.from_address if tenant_email else None,
            getattr(settings, "smtp_from_address", None),
        ),
    )


def resolve_pagopa_config(
    tenant_cfg: TenantConfig,
    settings,
) -> PagopaConfig:
    tenant_pagopa = tenant_cfg.pagopa

    default_password = _coalesce(
        getattr(settings, "pagopa_password", None),
        _read_secret_file(getattr(settings, "pagopa_password_file", None)),
    )
    default_print_password = _coalesce(
        getattr(settings, "pagopa_print_password", None),
        _read_secret_file(getattr(settings, "pagopa_print_password_file", None)),
    )

    tenant_password = (
        tenant_pagopa.password.get_secret_value()
        if tenant_pagopa and tenant_pagopa.password
        else None
    )
    tenant_print_password = (
        tenant_pagopa.print_password.get_secret_value()
        if tenant_pagopa and tenant_pagopa.print_password
        else None
    )

    password = _coalesce(tenant_password, default_password)
    print_password = _coalesce(tenant_print_password, default_print_password)

    if password is None:
        raise ValueError(
            f"Configurazione PagoPA incompleta per tenant '{tenant_cfg.tenant}': "
            "password non disponibile"
        )

    if print_password is None:
        raise ValueError(
            f"Configurazione PagoPA incompleta per tenant '{tenant_cfg.tenant}': "
            "print_password non disponibile"
        )

    return PagopaConfig(
        username=_coalesce(
            tenant_pagopa.username if tenant_pagopa else None,
            getattr(settings, "pagopa_username", None),
        ),
        password=SecretStr(password),
        print_username=_coalesce(
            tenant_pagopa.print_username if tenant_pagopa else None,
            getattr(settings, "pagopa_print_username", None),
        ),
        print_password=SecretStr(print_password),
        service_url=_coalesce(
            tenant_pagopa.service_url if tenant_pagopa else None,
            getattr(settings, "pagopa_service_url", None),
        ),
        codipa=_coalesce(
            tenant_pagopa.codipa if tenant_pagopa else None,
            getattr(settings, "pagopa_codipa", None),
        ),
    )


def resolve_protocollo_config(
    tenant_cfg: TenantConfig,
    settings,
) -> ProtocolloConfig:
    tenant_protocollo = tenant_cfg.protocollo

    default_password = _coalesce(
        getattr(settings, "protocollo_password", None),
        _read_secret_file(getattr(settings, "protocollo_password_file", None)),
    )

    tenant_password = (
        tenant_protocollo.password.get_secret_value()
        if tenant_protocollo and tenant_protocollo.password
        else None
    )

    password = _coalesce(tenant_password, default_password)
    if password is None:
        raise ValueError(
            f"Configurazione protocollo incompleta per tenant '{tenant_cfg.tenant}': "
            "password non disponibile"
        )

    return ProtocolloConfig(
        base_url=_coalesce(
            tenant_protocollo.base_url if tenant_protocollo else None,
            getattr(settings, "protocollo_base_url", None),
        ),
        username=_coalesce(
            tenant_protocollo.username if tenant_protocollo else None,
            getattr(settings, "protocollo_username", None),
        ),
        password=SecretStr(password),
    )