"""
VSS Configuration Management

Pydantic BaseSettings for type-safe, environment-driven configuration.

All defaults are safe no-credential placeholders.  Actual values MUST be
supplied via environment variables or the .env file located at the project
root (vss/.env).  See .env.example for the full list of supported keys.

Naming convention
-----------------
Top-level fields:   VSS_<FIELD>               e.g. VSS_API_PORT=9090
Nested fields:      VSS_<SECTION>__<FIELD>    e.g. VSS_CLICKHOUSE__HOST=db.internal
"""

from pathlib import Path
from typing import List, Literal, Optional
from urllib.parse import quote_plus

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

# Resolve the .env file path relative to this file so it is always found
# regardless of the working directory the process is started from.
_ENV_FILE = Path(__file__).resolve().parent.parent / ".env"


# ---------------------------------------------------------------------------
# Sub-configs (plain BaseModel — values are injected via VSSSettings nesting)
# ---------------------------------------------------------------------------

class ClickHouseConfig(BaseModel):
    """ClickHouse connection configuration."""

    host: str = Field(default="clickhouse-db", description="ClickHouse host")
    port: int = Field(default=8123, ge=1, le=65535, description="ClickHouse HTTP port")
    database: str = Field(default="default", description="Target database")
    user: str = Field(default="matrice", description="ClickHouse username")
    password: str = Field(
        default="",
        description=(
            "ClickHouse password. "
            "Never hard-code — set VSS_CLICKHOUSE__PASSWORD in the environment."
        ),
    )
    table: str = Field(
        default="aggregated_analytics_final",
        description="Primary analytics table",
    )

    @property
    def http_url(self) -> str:
        return f"http://{self.host}:{self.port}"

    @property
    def sqlalchemy_url(self) -> str:
        """
        SQLAlchemy-compatible URI for LangChain's SQLDatabase.from_uri().

        Format: clickhousedb://user:password@host:port/database
        Requires clickhouse-connect>=0.7.0 (provides the SQLAlchemy dialect).
        Password is URL-encoded to safely handle special characters.
        """
        encoded_password = quote_plus(self.password) if self.password else ""
        auth = f"{self.user}:{encoded_password}@" if encoded_password else f"{self.user}@"
        return f"clickhousedb://{auth}{self.host}:{self.port}/{self.database}"


class VLMConfig(BaseModel):
    """Cosmos-Reason2-8B VLM configuration."""

    model_name: str = Field(
        default="nvidia/Cosmos-Reason2-8B",
        description="HuggingFace model ID served by vLLM",
    )
    endpoint: str = Field(
        default="http://localhost:8000/v1",
        description="vLLM OpenAI-compatible base URL",
    )
    max_tokens: int = Field(default=1024, ge=1)
    temperature: float = Field(default=0.1, ge=0.0, le=2.0)
    gpu_device: int = Field(default=1, ge=0, description="CUDA device index for vLLM")
    gpu_memory_utilization: float = Field(
        default=0.85, gt=0.0, le=1.0, description="vLLM GPU memory fraction"
    )


class LLMConfig(BaseModel):
    """Llama 3.1 8B LLM configuration."""

    model_name: str = Field(default="llama3.1:8b", description="Ollama model tag")
    endpoint: str = Field(
        default="http://localhost:11434",
        description="Ollama base URL",
    )
    max_tokens: int = Field(default=512, ge=1)
    temperature: float = Field(default=0.1, ge=0.0, le=2.0)
    gpu_device: int = Field(default=0, ge=0, description="CUDA device index for Ollama")
    use_vllm: bool = Field(
        default=False,
        description="When True, route LLM traffic through the vLLM backend",
    )
    vllm_endpoint: str = Field(
        default="http://localhost:8001/v1",
        description="vLLM base URL used when use_vllm=True",
    )


# ---------------------------------------------------------------------------
# Main settings
# ---------------------------------------------------------------------------

class VSSSettings(BaseSettings):
    """
    Main VSS configuration.

    Environment variables override defaults using the VSS_ prefix and __
    as the nested-model delimiter.  The .env file at vss/.env is loaded
    automatically.

    Examples::

        VSS_API_PORT=9090
        VSS_LOG_LEVEL=DEBUG
        VSS_CLICKHOUSE__HOST=db.internal
        VSS_CLICKHOUSE__PASSWORD=s3cr3t
        VSS_LLM__ENDPOINT=http://gpu01:11434
        VSS_CORS_ALLOWED_ORIGINS=["https://app.example.com"]
    """

    model_config = SettingsConfigDict(
        env_prefix="VSS_",
        env_nested_delimiter="__",
        env_file=str(_ENV_FILE),
        env_file_encoding="utf-8",
        case_sensitive=False,
        extra="ignore",
    )

    # ── Service ────────────────────────────────────────────────────────────
    service_name: str = "vss"
    api_host: str = "0.0.0.0"
    api_port: int = Field(default=8080, ge=1, le=65535)
    log_level: str = Field(default="INFO", pattern="^(DEBUG|INFO|WARNING|ERROR|CRITICAL)$")

    # ── Security ───────────────────────────────────────────────────────────
    cors_allowed_origins: List[str] = Field(
        default=["*"],
        description=(
            "CORS allowed origins list. "
            "Restrict to explicit origins in production, e.g. "
            'VSS_CORS_ALLOWED_ORIGINS=\'["https://app.example.com"]\''
        ),
    )

    # ── Components ─────────────────────────────────────────────────────────
    clickhouse: ClickHouseConfig = ClickHouseConfig()
    vlm: VLMConfig = VLMConfig()
    llm: LLMConfig = LLMConfig()

    # ── Feature flags ──────────────────────────────────────────────────────
    vlm_enabled: bool = Field(
        default=False,
        description=(
            "Enable the VLM (Cosmos-Reason2-8B) path. "
            "When False, /query/media returns 503 and VLM health shows 'disabled'. "
            "Set VSS_VLM_ENABLED=true to enable."
        ),
    )

    # ── Agent settings ─────────────────────────────────────────────────────
    sql_max_retries: int = Field(default=2, ge=0)
    enable_vlm_escalation: bool = Field(
        default=False,
        description=(
            "Allow SQL agent to escalate to VLM when results are insufficient. "
            "Has no effect when vlm_enabled=False."
        ),
    )

    # ── SQL-agent LangChain tuning ─────────────────────────────────────────
    sql_dialect: str = Field(
        default="clickhouse",
        description="SQL dialect passed to the LangChain query-checker and generation prompts",
    )
    sql_top_k_tables: int = Field(
        default=5,
        ge=1,
        description="Max candidate tables forwarded to the LLM for table selection",
    )
    sql_sample_rows_per_table: int = Field(
        default=0,
        ge=0,
        description="Sample rows shown per table in LangChain schema info (0 = none)",
    )
    sql_schema_loading_mode: Literal["selected_tables", "all_tables"] = Field(
        default="selected_tables",
        description=(
            "'selected_tables' lets the LLM pick relevant tables; "
            "'all_tables' loads every table schema unconditionally"
        ),
    )
    sql_enforce_read_only: bool = Field(
        default=True,
        description="Block any non-SELECT/WITH SQL at the query-tool level",
    )

# ---------------------------------------------------------------------------
# Singleton accessor
# ---------------------------------------------------------------------------

_settings: Optional[VSSSettings] = None


def get_settings() -> VSSSettings:
    """Return the cached VSSSettings singleton, creating it on first call."""
    global _settings
    if _settings is None:
        _settings = VSSSettings()
    return _settings
