"""
TLS configuration for client and server connections.

Provides unified TLS configuration that can be shared across services.
"""

from pathlib import Path
from typing import Optional

from pydantic import Field, model_validator
from pydantic_settings import BaseSettings, SettingsConfigDict


class TLSConfig(BaseSettings):
    """
    Shared TLS configuration for client connections.

    Can be configured via environment variables with TLS_ prefix:
        TLS_CA_PATH=certs/ca.crt
        TLS_CERT_PATH=certs/client.crt
        TLS_KEY_PATH=certs/client.key
    """

    model_config = SettingsConfigDict(
        env_prefix="TLS_",
        env_file=".env",
        extra="ignore",
    )

    ca_path: Optional[str] = Field(
        default=None,
        description="Path to CA certificate for verifying server",
    )
    cert_path: Optional[str] = Field(
        default=None,
        description="Path to client certificate for mTLS",
    )
    key_path: Optional[str] = Field(
        default=None,
        description="Path to client private key for mTLS",
    )

    def load_ca_cert(self) -> Optional[bytes]:
        """Load CA certificate bytes."""
        if self.ca_path and Path(self.ca_path).exists():
            return Path(self.ca_path).read_bytes()
        return None

    def load_cert(self) -> Optional[bytes]:
        """Load certificate bytes."""
        if self.cert_path and Path(self.cert_path).exists():
            return Path(self.cert_path).read_bytes()
        return None

    def load_key(self) -> Optional[bytes]:
        """Load private key bytes."""
        if self.key_path and Path(self.key_path).exists():
            return Path(self.key_path).read_bytes()
        return None

    @property
    def is_configured(self) -> bool:
        """Check if TLS is fully configured for mTLS."""
        return all([self.ca_path, self.cert_path, self.key_path])

    @property
    def has_ca(self) -> bool:
        """Check if CA is configured (minimum for TLS)."""
        return self.ca_path is not None


class ServerTLSConfig(BaseSettings):
    """
    TLS configuration for servers.

    Supports both simple TLS (server cert only) and mTLS (with client verification).
    """

    model_config = SettingsConfigDict(
        env_file=".env",
        extra="ignore",
    )

    use_tls: bool = Field(
        default=False,
        description="Whether to use TLS",
    )
    require_client_auth: bool = Field(
        default=True,
        description="Whether to require client certificates (mTLS)",
    )
    cert_path: Optional[str] = Field(
        default=None,
        description="Path to server certificate",
    )
    key_path: Optional[str] = Field(
        default=None,
        description="Path to server private key",
    )
    ca_path: Optional[str] = Field(
        default=None,
        description="Path to CA certificate for client verification",
    )

    def load_cert(self) -> Optional[bytes]:
        """Load server certificate bytes."""
        if self.cert_path and Path(self.cert_path).exists():
            return Path(self.cert_path).read_bytes()
        return None

    def load_key(self) -> Optional[bytes]:
        """Load server private key bytes."""
        if self.key_path and Path(self.key_path).exists():
            return Path(self.key_path).read_bytes()
        return None

    def load_ca_cert(self) -> Optional[bytes]:
        """Load CA certificate bytes."""
        if self.ca_path and Path(self.ca_path).exists():
            return Path(self.ca_path).read_bytes()
        return None

    @property
    def tls_configured(self) -> bool:
        """Check if TLS is fully configured (has cert and key)."""
        return all([self.cert_path, self.key_path])


# Global shared TLS config instance for clients
_shared_tls_config: Optional[TLSConfig] = None


def get_shared_tls_config() -> TLSConfig:
    """Get or create the shared TLS configuration."""
    global _shared_tls_config
    if _shared_tls_config is None:
        _shared_tls_config = TLSConfig()
    return _shared_tls_config


class TLSConfigWithFallback(TLSConfig):
    """
    TLS configuration that falls back to shared TLS_ env vars.

    Useful for service-specific configs that should inherit from global TLS settings.
    """

    @model_validator(mode="after")
    def apply_tls_fallback(self) -> "TLSConfigWithFallback":
        """Fall back to shared TLS_ config for unset paths."""
        shared = get_shared_tls_config()
        if self.ca_path is None:
            self.ca_path = shared.ca_path
        if self.cert_path is None:
            self.cert_path = shared.cert_path
        if self.key_path is None:
            self.key_path = shared.key_path
        return self
