"""Configuration loaded from environment / .env file."""

from __future__ import annotations

from pydantic import Field
from pydantic_settings import BaseSettings

from proxym.utils.get_settings import get_singleton


class Settings(BaseSettings):
    """All settings with sensible defaults. Override via env vars or .env file."""

    model_config = {"env_file": ".env", "env_file_encoding": "utf-8", "extra": "ignore"}

    # --- Server ---
    host: str = Field("0.0.0.0", alias="AI_PROXY_HOST")
    port: int = Field(4000, alias="AI_PROXY_PORT")
    default_proxy_url: str = Field("http://localhost:4000", alias="DEFAULT_PROXY_URL")
    default_api_key: str = Field("sk-proxy-local-dev", alias="DEFAULT_API_KEY")
    master_key: str = Field("sk-proxy-local-dev", alias="AI_PROXY_MASTER_KEY")
    log_level: str = Field("info", alias="AI_PROXY_LOG_LEVEL")

    # --- Redis ---
    redis_url: str = Field("redis://localhost:6379/0", alias="REDIS_URL")

    # --- Provider keys ---
    anthropic_api_key: str = Field("", alias="ANTHROPIC_API_KEY")
    openai_api_key: str = Field("", alias="OPENAI_API_KEY")
    openrouter_api_key: str = Field("", alias="OPENROUTER_API_KEY")
    google_ai_key: str = Field("", alias="GOOGLE_AI_KEY")
    deepseek_api_key: str = Field("", alias="DEEPSEEK_API_KEY")
    groq_api_key: str = Field("", alias="GROQ_API_KEY")
    together_api_key: str = Field("", alias="TOGETHER_API_KEY")
    mistral_api_key: str = Field("", alias="MISTRAL_API_KEY")
    fireworks_api_key: str = Field("", alias="FIREWORKS_API_KEY")
    cerebras_api_key: str = Field("", alias="CEREBRAS_API_KEY")

    # --- Local Ollama ---
    ollama_base_url: str = Field("http://localhost:11434", alias="OLLAMA_BASE_URL")
    ollama_secondary_url: str = Field("", alias="OLLAMA_SECONDARY_URL")

    # --- Delta context buffer ---
    watch_dir: str = Field("./project", alias="WATCH_DIR")
    max_context_tokens: int = Field(120_000, alias="MAX_CONTEXT_TOKENS")
    delta_threshold: float = Field(0.15, alias="DELTA_THRESHOLD")

    # --- Budget ---
    monthly_budget_usd: float = Field(60.0, alias="MONTHLY_BUDGET_USD")
    daily_budget_usd: float = Field(5.0, alias="DAILY_BUDGET_USD")
    max_request_cost_usd: float = Field(2.0, alias="MAX_REQUEST_COST_USD")

    # --- VM / CloneBox ---
    projects_root: str = Field("~/github", alias="PROJECTS_ROOT")
    profiles_dir: str = Field("~/.config/proxym/profiles", alias="PROFILES_DIR")

    # --- Default Models (direct registry IDs, no aliases) ---
    default_model: str = Field(
        "google/gemini-3-flash-preview",
        alias="PROXYM_DEFAULT_MODEL",
    )
    fallback_model: str = Field(
        "google/gemini-2.5-flash",
        alias="PROXYM_FALLBACK_MODEL",
    )
    local_model: str = Field(
        "ollama/qwen2.5-coder-7b",
        alias="PROXYM_LOCAL_MODEL",
    )

    # --- Dashboard & Client Configuration ---
    dashboard_api_url: str = Field("http://localhost:4000", alias="DASHBOARD_API_URL")

    # --- VS Code Web ---
    vscode_enabled: bool = Field(False, alias="VSCODE_ENABLED")
    vscode_port: int = Field(8080, alias="VSCODE_PORT")
    vscode_password: str = Field("proxym-vscode", alias="VSCODE_PASSWORD")
    vscode_project_path: str = Field("./", alias="VSCODE_PROJECT_PATH")
    vscode_workspace_name: str = Field("proxym", alias="VSCODE_WORKSPACE_NAME")

    # --- Observability ---
    log_buffer_size: int = Field(1000, alias="PROXYM_LOG_BUFFER_SIZE")
    watchdog_enabled: bool = Field(True, alias="PROXYM_WATCHDOG_ENABLED")
    watchdog_interval: int = Field(60, alias="PROXYM_WATCHDOG_INTERVAL")

    # --- Self-healing ---
    repair_enabled: bool = Field(False, alias="PROXYM_REPAIR_ENABLED")
    repair_mode: str = Field("suggest", alias="PROXYM_REPAIR_MODE")
    repair_api_key: str = Field("", alias="PROXYM_REPAIR_API_KEY")
    repair_model: str = Field("google/gemini-2.5-flash", alias="PROXYM_REPAIR_MODEL")
    repair_budget_daily: float = Field(2.0, alias="PROXYM_REPAIR_BUDGET_DAILY")

    # --- Tools ---
    tools_available: str = Field("", alias="PROXYM_TOOLS_AVAILABLE")
    tool_providers: dict[str, str] = Field(
        default_factory=lambda: {
            "aider": "openrouter",
            "claude-code": "anthropic",
            "windsurf": "openrouter",
            "cursor": "openrouter",
            "vscode": "openrouter",
            "roo-code": "openrouter",
            "cline": "openrouter",
            "browser": "openrouter",
        },
        alias="PROXYM_TOOL_PROVIDERS",
    )

    # --- Development ---
    dev_port: int = Field(4001, alias="DEV_PORT")
    debug: bool = Field(False, alias="DEBUG")
    hot_reload: bool = Field(False, alias="HOT_RELOAD")

    def available_providers(self) -> dict[str, str]:
        """Return mapping of provider name → api key for configured providers."""
        providers = {}
        key_map = {
            "anthropic": self.anthropic_api_key,
            "openai": self.openai_api_key,
            "openrouter": self.openrouter_api_key,
            "google": self.google_ai_key,
            "deepseek": self.deepseek_api_key,
            "groq": self.groq_api_key,
            "together": self.together_api_key,
            "mistral": self.mistral_api_key,
            "fireworks": self.fireworks_api_key,
            "cerebras": self.cerebras_api_key,
        }
        for name, key in key_map.items():
            if key:
                providers[name] = key
        # Ollama is always available (local)
        providers["ollama"] = "ollama"
        return providers

    def resolve_model_alias(self, model_str: str) -> str:
        """Resolve a model string to a litellm model name.

        Tries in order:
        1. Direct registry lookup (by ID / litellm_model / partial match)
        2. Backward-compatible alias mapping (cheap/balanced/smart/…)
        3. Return original string as-is

        Args:
            model_str: Model registry ID (e.g. "google/gemini-3-flash-preview"),
                       litellm name, or legacy alias

        Returns:
            The litellm_model string, or the original string if not found
        """
        from proxym.providers import resolve_model as _resolve
        # 1. Direct registry lookup
        spec = _resolve(model_str)
        if spec:
            return spec.litellm_model
        # 2. Backward-compatible alias → registry ID → litellm_model
        alias_target = self.model_aliases.get(model_str)
        if alias_target:
            spec = _resolve(alias_target)
            if spec:
                return spec.litellm_model
        return model_str

    @property
    def model_aliases(self) -> dict[str, str]:
        """Backward-compatible alias dict derived from default models.

        Maps old alias names to registry model IDs for code that still
        references aliases during migration.
        """
        return {
            "cheap": self.fallback_model,
            "balanced": self.default_model,
            "smart": self.default_model,
            "premium": "anthropic/opus-4.6",
            "free": self.fallback_model,
            "local": self.local_model,
        }


_settings: Settings | None = None


def get_settings() -> Settings:
    global _settings
    _settings = get_singleton(_settings, Settings)
    return _settings
