"""
config.py — Configuration loading and validation.

Loaded once at startup. Fails fast if required variables are missing.
All other modules import `settings` from here.
"""
from __future__ import annotations

import os
import re
import sys
from dataclasses import dataclass, field
from pathlib import Path

from dotenv import load_dotenv

# Load .env from the project root (one level above server/)
_env_path = Path(__file__).parent.parent / ".env"
load_dotenv(_env_path)


_PROJECT_ROOT = Path(__file__).parent.parent


def _extract_agent_name(fallback: str = "Jarvis") -> str:
    """Read agent name from SOUL.md. Looks for 'You are **Name**', then the # heading."""
    try:
        soul = (_PROJECT_ROOT / "SOUL.md").read_text(encoding="utf-8")
    except FileNotFoundError:
        return fallback
    # Primary: "You are **Name**"
    m = re.search(r"You are \*\*([^*]+)\*\*", soul)
    if m:
        return m.group(1).strip()
    # Fallback: first "# Name" heading, dropping anything after " — "
    for line in soul.splitlines():
        if line.startswith("# "):
            name = line[2:].split("—")[0].strip()
            if name:
                return name
    return fallback


def _require(key: str) -> str:
    """Get a required environment variable, fail fast if missing."""
    value = os.getenv(key)
    if not value:
        print(f"[aide] FATAL: Required environment variable '{key}' is not set.", file=sys.stderr)
        print(f"[aide] Copy .env.example to .env and fill in your values.", file=sys.stderr)
        sys.exit(1)
    return value


def _optional(key: str, default: str = "") -> str:
    return os.getenv(key, default)


@dataclass
class Settings:
    # Required
    db_master_password: str

    # AI provider selection — keys are stored in the DB, not here
    default_provider: str = "anthropic"  # "anthropic", "openrouter", or "openai"
    default_model: str = ""              # Empty = use provider's default model

    # Optional with defaults
    port: int = 8080
    max_tool_calls: int = 20
    max_autonomous_runs_per_hour: int = 10
    timezone: str = "Europe/Oslo"

    # Agent identity — derived from SOUL.md at startup, fallback if file absent
    agent_name: str = "Jarvis"

    # Model selection — empty list triggers auto-discovery at runtime
    available_models: list[str] = field(default_factory=list)
    default_chat_model: str = ""

    # Database
    aide_db_url: str = ""


def _load() -> Settings:
    master_password = _require("DB_MASTER_PASSWORD")

    default_provider = _optional("DEFAULT_PROVIDER", "anthropic").lower()
    default_model = _optional("DEFAULT_MODEL", "")

    _known_providers = {"anthropic", "openrouter", "openai"}
    if default_provider not in _known_providers:
        print(f"[aide] FATAL: Unknown DEFAULT_PROVIDER '{default_provider}'. Use 'anthropic', 'openrouter', or 'openai'.", file=sys.stderr)
        sys.exit(1)

    port = int(_optional("PORT", "8080"))
    max_tool_calls = int(_optional("MAX_TOOL_CALLS", "20"))
    max_runs = int(_optional("MAX_AUTONOMOUS_RUNS_PER_HOUR", "10"))
    timezone = _optional("TIMEZONE", "Europe/Oslo")

    available_models: list[str] = []
    default_chat_model_raw = _optional("DEFAULT_CHAT_MODEL", "")
    if default_chat_model_raw and ":" not in default_chat_model_raw:
        default_chat_model = f"{default_provider}:{default_chat_model_raw}"
    else:
        default_chat_model = default_chat_model_raw

    aide_db_url = _require("AIDE_DB_URL")

    return Settings(
        agent_name=_extract_agent_name(),
        db_master_password=master_password,
        default_provider=default_provider,
        default_model=default_model,
        port=port,
        max_tool_calls=max_tool_calls,
        max_autonomous_runs_per_hour=max_runs,
        timezone=timezone,
        available_models=available_models,
        default_chat_model=default_chat_model,
        aide_db_url=aide_db_url,
    )


# Module-level singleton — import this everywhere
settings = _load()
