"""Configuration management for the Radix Edge Agent."""

from __future__ import annotations

import os
import platform
from typing import Optional

from pydantic import Field
from pydantic_settings import BaseSettings


def _default_db_path() -> str:
    """Return a platform-aware default path for the SQLite database."""
    system = platform.system()
    if system == "Darwin":
        return os.path.expanduser("~/Library/Application Support/radix/edge.db")
    elif system == "Windows":
        appdata = os.environ.get("APPDATA", os.path.expanduser("~\\AppData\\Roaming"))
        return os.path.join(appdata, "radix", "edge.db")
    else:
        # Linux and other POSIX systems
        return os.path.expanduser("~/.local/share/radix/edge.db")


def _default_jobs_workdir() -> str:
    """Return a platform-aware default path for the jobs workspace."""
    system = platform.system()
    if system == "Windows":
        temp = os.environ.get("TEMP", os.environ.get("TMP", os.path.expanduser("~\\AppData\\Local\\Temp")))
        return os.path.join(temp, "radix-jobs")
    else:
        # Linux, macOS, and other POSIX systems
        return "/tmp/radix-jobs"


class EdgeConfig(BaseSettings):
    """All edge agent configuration, driven by environment variables."""

    model_config = {"env_prefix": "RADIX_", "case_sensitive": False}

    # --- Server ---
    host: str = Field(default="0.0.0.0", description="API listen address")
    port: int = Field(default=8080, description="API listen port")
    log_level: str = Field(default="INFO", description="Log level")
    auth_token: str = Field(default="", description="Bearer token for API authentication")

    # --- Storage ---
    db_path: str = Field(default_factory=_default_db_path, description="SQLite database path")
    jobs_workdir: str = Field(default_factory=_default_jobs_workdir, description="Job workspace directory")

    # --- Observer ---
    observer_interval: float = Field(default=5.0, description="GPU polling interval in seconds")
    observer_retention_hours: int = Field(default=24, description="GPU observation retention")

    # --- Scheduler (information-theoretic model) ---
    scheduler_policy: str = Field(default="priority", description="Scheduling policy: fifo, priority, fairshare, sjf")
    lambda_uncertainty: float = Field(default=0.3, description="Uncertainty weight (λ)")
    beta_exploration: float = Field(default=0.7, description="Information gain weight (β)")
    gamma_interference: float = Field(default=0.0, description="Interference penalty weight (γ)")
    delta_topology: float = Field(default=0.5, description="Topology mismatch penalty weight (δ)")
    tau_squared: float = Field(default=0.15, description="Observation noise variance (τ²)")
    exploration_cap: float = Field(default=0.25, description="Maximum exploration ratio")
    enable_interference: bool = Field(default=False, description="Enable interference learning")
    enable_sinkhorn: bool = Field(default=False, description="Enable Sinkhorn batch assignment")
    retention_observations: int = Field(default=1000, description="Max observations per (job_type, gpu_type)")

    # --- Executor ---
    default_timeout: int = Field(default=3600, description="Default job timeout in seconds")
    max_concurrent_jobs: int = Field(default=16, description="Maximum concurrent running jobs")

    # --- Security ---
    allowed_image_patterns: str = Field(
        default="",
        description="Comma-separated list of allowed Docker image regex patterns (empty = allow all)"
    )
    job_memory_limit: str = Field(default="16g", description="Docker memory limit for job containers")
    job_cpu_limit: str = Field(default="4", description="Docker CPU limit for job containers")
    job_pids_limit: int = Field(default=4096, description="Docker PID limit for job containers")
    job_network_mode: str = Field(default="none", description="Docker network mode for job containers (none, bridge, host)")

    # --- Enforcer ---
    default_max_concurrent_gpu_jobs: int = Field(default=2, description="Default per-user concurrent GPU job limit")
    default_max_gpus_total: int = Field(default=4, description="Default per-user total GPU limit")
    default_fair_share_weight: float = Field(default=1.0, description="Default fair share weight")
    rate_limit_requests_per_min: int = Field(default=600, description="API rate limit per user per minute")

    # --- FEP Meta-Agent ---
    fep_enabled: bool = Field(default=True, description="Enable FEP meta-agent")
    fep_interval: float = Field(default=15.0, description="FEP evaluation interval in seconds")

    # --- Brain Auto-Tuner ---
    autotuner_enabled: bool = Field(default=True, description="Enable brain auto-tuner")
    autotuner_interval: float = Field(default=60.0, description="Auto-tuner interval in seconds")
    autotuner_min_jobs: int = Field(default=10, description="Minimum completed jobs before adjustment")
    autotuner_max_delta: float = Field(default=0.05, description="Maximum weight change per cycle")

    # --- Mesh (Tier 2) ---
    mesh_enabled: bool = Field(default=False, description="Enable mesh peer-to-peer mode")
    mesh_key: str = Field(default="", description="Pre-shared key for mesh authentication")
    mesh_peers: str = Field(default="", description="Manual peer addresses (host:port,host:port)")
    mesh_heartbeat_interval: float = Field(default=5.0, description="Mesh heartbeat interval seconds")
    mesh_discovery_interval: float = Field(default=10.0, description="mDNS discovery interval seconds")
    mesh_stale_threshold: float = Field(default=15.0, description="Peer stale threshold seconds")
    mesh_node_id: str = Field(default="", description="Node ID (auto-generated UUID if empty)")

    # --- Upstream Control Plane ---
    upstream_enabled: bool = Field(default=False, description="Enable upstream control plane communication")
    api_base: str = Field(default="", description="Control plane API base URL")
    cluster_id: str = Field(default="", description="Cluster ID for control plane registration")
    tenant_id: str = Field(default="", description="Tenant ID for control plane authentication")
    cluster_token: str = Field(default="", description="Long-lived cluster authentication token")
    one_time_token: str = Field(default="", description="One-time onboarding token (exchanged on first run)")
    token_file: str = Field(default="/var/lib/radix/cluster_token", description="Path to persist cluster token")
    heartbeat_interval: float = Field(default=60.0, description="Heartbeat interval in seconds")
    job_poll_interval: float = Field(default=10.0, description="Job polling interval in seconds")


_config: Optional[EdgeConfig] = None


def get_config() -> EdgeConfig:
    """Get the global configuration instance."""
    global _config
    if _config is None:
        _config = EdgeConfig()
    return _config


def reset_config():
    """Reset config (for testing)."""
    global _config
    _config = None
