"""
Brynq Runtime — Configuration.

Centralized configuration for the local runtime that runs on the user's
machine. All values can be overridden via environment variables prefixed
with BRYNQ_RUNTIME_.

Defaults are safe for local development. In production (packaged binary),
DATA_DIR resolves to ~/.brynq/ and CLOUD_URL points to api.brynq.ai.
"""

from __future__ import annotations

import os
from dataclasses import dataclass
from pathlib import Path


def _default_data_dir() -> Path:
    """~/.brynq/ on all platforms."""
    return Path.home() / ".brynq"


@dataclass(frozen=True)
class RuntimeConfig:
    """Immutable runtime configuration loaded at startup.

    Attributes:
        cloud_url:        Base URL for the Brynq Cloud API.
        local_port:       Port the local FastAPI server listens on.
        ollama_url:       Ollama REST API base URL.
        data_dir:         Local data directory for keys, logs, agent cache.
        plan_verify_key:  Shared secret for HMAC plan verification.
        cloud_timeout:    HTTP timeout (seconds) for cloud requests.
        ollama_timeout:   HTTP timeout (seconds) for Ollama requests.
        debug:            Enable verbose logging and auto-reload.
    """

    cloud_url: str = "https://api.brynq.ai"
    local_port: int = 8003
    ollama_url: str = "http://localhost:11434"
    data_dir: Path = None  # type: ignore[assignment]  # set in __post_init__
    plan_verify_key: str = ""
    cloud_timeout: float = 30.0
    ollama_timeout: float = 120.0
    debug: bool = False

    def __post_init__(self) -> None:
        # Frozen dataclass — use object.__setattr__ for defaults
        if self.data_dir is None:
            object.__setattr__(self, "data_dir", _default_data_dir())

    @classmethod
    def from_env(cls) -> RuntimeConfig:
        """Create a RuntimeConfig with short-name env var overrides.

        Checks ``BRYNQ_CLOUD_URL``, ``BRYNQ_OLLAMA_URL``, and
        ``BRYNQ_PORT`` environment variables and uses them if set,
        overriding the dataclass defaults.
        """
        overrides: dict = {}

        cloud_url = os.getenv("BRYNQ_CLOUD_URL")
        if cloud_url is not None:
            overrides["cloud_url"] = cloud_url.rstrip("/")

        ollama_url = os.getenv("BRYNQ_OLLAMA_URL")
        if ollama_url is not None:
            overrides["ollama_url"] = ollama_url.rstrip("/")

        port = os.getenv("BRYNQ_PORT")
        if port is not None:
            overrides["local_port"] = int(port)

        return cls(**overrides)

    def validate(self) -> None:
        """Validate configuration values.

        Raises:
            ValueError: If any configuration value is invalid.
        """
        if not self.ollama_url.startswith(("http://", "https://")):
            raise ValueError(
                f"ollama_url must start with 'http://' or 'https://', got '{self.ollama_url}'"
            )
        if not (1024 <= self.local_port <= 65535):
            raise ValueError(
                f"local_port must be between 1024 and 65535, got {self.local_port}"
            )
        if not self.cloud_url:
            raise ValueError("cloud_url must not be empty")


def load_config() -> RuntimeConfig:
    """Load configuration from environment variables.

    Every field can be set via BRYNQ_RUNTIME_{FIELD_NAME} in uppercase.
    Example: BRYNQ_RUNTIME_CLOUD_URL, BRYNQ_RUNTIME_LOCAL_PORT.

    Returns:
        RuntimeConfig with environment overrides applied.
    """
    data_dir_env = os.getenv("BRYNQ_RUNTIME_DATA_DIR")
    data_dir = Path(data_dir_env) if data_dir_env else _default_data_dir()

    return RuntimeConfig(
        cloud_url=os.getenv("BRYNQ_RUNTIME_CLOUD_URL", "https://api.brynq.ai").rstrip("/"),
        local_port=int(os.getenv("BRYNQ_RUNTIME_LOCAL_PORT", "8003")),
        ollama_url=os.getenv("BRYNQ_RUNTIME_OLLAMA_URL", "http://localhost:11434").rstrip("/"),
        data_dir=data_dir,
        plan_verify_key=os.getenv("BRYNQ_RUNTIME_PLAN_VERIFY_KEY", ""),
        cloud_timeout=float(os.getenv("BRYNQ_RUNTIME_CLOUD_TIMEOUT", "30.0")),
        ollama_timeout=float(os.getenv("BRYNQ_RUNTIME_OLLAMA_TIMEOUT", "120.0")),
        debug=os.getenv("BRYNQ_RUNTIME_DEBUG", "0") == "1",
    )
