"""Application configuration via pydantic-settings + YAML merge."""
from __future__ import annotations

import functools
from pathlib import Path
from typing import Any

import yaml
from pydantic import field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict


def _load_yaml(path: str | Path) -> dict[str, Any]:
    p = Path(path)
    if p.exists():
        with open(p) as f:
            return yaml.safe_load(f) or {}
    return {}


class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        case_sensitive=False,
        extra="ignore",
    )

    app_env: str = "dev"

    # Stock Oracle
    stock_oracle_url: str = "http://localhost:18001"
    stock_oracle_timeout: int = 30

    # Database
    postgres_dsn: str = "postgresql+asyncpg://acef:acef@localhost:5432/acef"

    # File storage
    data_root: str = "./data"
    earnings_calendar_pit_file: str | None = None

    # Symbol universe
    symbols_file: str = "configs/symbols.yaml"

    # Logging
    log_level: str = "INFO"

    # LLM (OpenAI — legacy placeholder)
    openai_api_key: str = "sk-placeholder"
    llm_enabled: bool = False

    # Ollama
    ollama_url: str = "http://localhost:11434"
    ollama_model: str = "llama3.2"
    ollama_timeout: int = 600

    # App YAML overrides (loaded separately)
    _app_config: dict[str, Any] = {}

    @field_validator("log_level")
    @classmethod
    def normalize_log_level(cls, v: str) -> str:
        return v.upper()

    @property
    def exhibit_cache_dir(self) -> Path:
        return Path(self.data_root) / "cache" / "exhibits"

    @property
    def parquet_dir(self) -> Path:
        return Path(self.data_root) / "parquet"

    @property
    def earnings_calendar_pit_path(self) -> Path:
        if self.earnings_calendar_pit_file:
            return Path(self.earnings_calendar_pit_file)
        return Path(self.data_root) / "reference" / "earnings_calendar_pit.parquet"

    def get_app_config(self) -> dict[str, Any]:
        if not self._app_config:
            object.__setattr__(self, "_app_config", _load_yaml("configs/app.yaml"))
        return self._app_config

    def get_symbols(self) -> list[str]:
        cfg = _load_yaml(self.symbols_file)
        return cfg.get("symbols", [])

    def get_fred_series(self) -> list[dict[str, Any]]:
        cfg = _load_yaml("configs/fred_series.yaml")
        return cfg.get("series", [])


@functools.lru_cache(maxsize=1)
def get_settings() -> Settings:
    return Settings()
