from functools import lru_cache
from typing import List, Optional

from pydantic import AliasChoices, BaseModel, Field, computed_field
from pydantic_settings import BaseSettings, SettingsConfigDict


class FirebaseSettings(BaseModel):
    project_id: str
    storage_bucket: Optional[str] = None


class VertexAISettings(BaseModel):
    project_id: str
    location: str = "us-central1"
    model: str = "publishers/google/models/gemini-2.5-flash-lite-preview-02-05"


class FirestoreSettings(BaseModel):
    emulator_host: Optional[str] = None
    credentials_path: Optional[str] = None


class DlpSettings(BaseModel):
    project_id: Optional[str] = None
    location: str = "global"
    deidentify_template: Optional[str] = None


class GatewaySettings(BaseSettings):
    model_config = SettingsConfigDict(
        env_file=(".env", ".env.local"),
        extra="ignore",
        env_nested_delimiter="__",
    )

    environment: str = Field("development", alias="ENVIRONMENT")
    allowed_origins_raw: Optional[str] = Field(
        None,
        alias="ALLOWED_ORIGINS",
        validation_alias=AliasChoices("ALLOWED_ORIGINS"),
    )

    firebase_project_id: str = Field(
        ...,
        validation_alias=AliasChoices(
            "FIREBASE__PROJECT_ID",
            "FIREBASE__FIREBASE_PROJECT_ID",
            "FIREBASE_PROJECT_ID",
        ),
    )
    firebase_storage_bucket: Optional[str] = Field(
        None,
        validation_alias=AliasChoices(
            "FIREBASE__STORAGE_BUCKET",
            "FIREBASE__FIREBASE_STORAGE_BUCKET",
            "FIREBASE_STORAGE_BUCKET",
        ),
    )

    firestore_emulator_host: Optional[str] = Field(
        None,
        validation_alias=AliasChoices(
            "FIRESTORE__EMULATOR_HOST",
            "FIRESTORE_EMULATOR_HOST",
        ),
    )
    firebase_credentials_path: Optional[str] = Field(
        None,
        validation_alias=AliasChoices(
            "FIREBASE__CREDENTIALS_PATH",
            "FIREBASE_CREDENTIALS_PATH",
        ),
    )

    vertex_project_id: str = Field(
        ...,
        validation_alias=AliasChoices(
            "VERTEX__PROJECT_ID",
            "VERTEX_PROJECT_ID",
        ),
    )
    vertex_location: str = Field(
        "us-central1",
        validation_alias=AliasChoices(
            "VERTEX__LOCATION",
            "VERTEX_LOCATION",
        ),
    )
    vertex_model: str = Field(
        "publishers/google/models/gemini-2.0-flash-lite-preview-02-05",
        validation_alias=AliasChoices(
            "VERTEX__MODEL",
            "VERTEX_MODEL",
        ),
    )

    dlp_project_id: Optional[str] = Field(
        None,
        validation_alias=AliasChoices(
            "DLP__PROJECT_ID",
            "DLP_PROJECT_ID",
        ),
    )
    dlp_location: str = Field(
        "global",
        validation_alias=AliasChoices(
            "DLP__LOCATION",
            "DLP_LOCATION",
        ),
    )
    dlp_deidentify_template: Optional[str] = Field(
        None,
        validation_alias=AliasChoices(
            "DLP__DEIDENTIFY_TEMPLATE",
            "DLP_DEIDENTIFY_TEMPLATE",
        ),
    )

    # Scanner settings
    scanner_save_tests: bool = Field(
        False,
        alias="SCANNER_SAVE_TESTS",
        description="If true, persist Giskard test suites to disk and execute them",
    )

    # Firewall pre-classifier settings
    firewall_preclassifier_enabled: bool = Field(
        True,
        alias="FIREWALL_PRECLASSIFIER_ENABLED",
        description="Run a deterministic pre-classification stage before LLM analysis",
    )
    firewall_preclassifier_short_circuit: bool = Field(
        True,
        alias="FIREWALL_PRECLASSIFIER_SHORT_CIRCUIT",
        description="If true, skip the LLM stage when the pre-classifier decides to allow",
    )

    @computed_field
    @property
    def firebase(self) -> FirebaseSettings:
        return FirebaseSettings(
            project_id=self.firebase_project_id,
            storage_bucket=self.firebase_storage_bucket,
        )

    @computed_field
    @property
    def allowed_origins(self) -> List[str]:
        if not self.allowed_origins_raw:
            return []
        return [origin.strip() for origin in self.allowed_origins_raw.split(",") if origin.strip()]

    @computed_field
    @property
    def firestore(self) -> FirestoreSettings:
        return FirestoreSettings(
            emulator_host=self.firestore_emulator_host,
            credentials_path=self.firebase_credentials_path,
        )

    @computed_field
    @property
    def vertex_ai(self) -> VertexAISettings:
        return VertexAISettings(
            project_id=self.vertex_project_id,
            location=self.vertex_location,
            model=self.vertex_model,
        )

    @computed_field
    @property
    def dlp(self) -> DlpSettings:
        return DlpSettings(
            project_id=self.dlp_project_id or self.firebase_project_id,
            location=self.dlp_location,
            deidentify_template=self.dlp_deidentify_template,
        )


@lru_cache
def get_settings() -> GatewaySettings:
    return GatewaySettings()  # type: ignore[call-arg]


__all__ = [
    "get_settings",
    "GatewaySettings",
    "FirebaseSettings",
    "VertexAISettings",
    "FirestoreSettings",
    "DlpSettings",
]
