"""Node configuration management (~/.rc/config.toml)."""

from __future__ import annotations

import os
import sys
import uuid
from dataclasses import dataclass
from pathlib import Path
from typing import Optional

import tomli_w
from rc.inference.catalog import get_default_model_repo

if sys.version_info >= (3, 11):
    import tomllib
else:
    import tomli as tomllib

RC_DIR = Path.home() / ".rc"
CONFIG_PATH = RC_DIR / "config.toml"
DEFAULT_BACKEND_URL = "https://capacitor-backend-egfucye9gjdcdram.canadacentral-01.azurewebsites.net"


def get_default_backend_url() -> str:
    """Allow env overrides while keeping the deployed backend as the default."""
    return os.environ.get("RC_BACKEND_URL", DEFAULT_BACKEND_URL).rstrip("/")


@dataclass
class NodeConfig:
    node_id: str = ""
    node_name: str = "default-node"
    role: str = "both"  # provider | requester | both
    node_secret: str = ""
    supabase_url: str = ""
    supabase_key: str = ""
    backend_url: str = DEFAULT_BACKEND_URL
    model: str = get_default_model_repo()
    model_path: str = ""
    model_downloaded: bool = False
    accelerator: str = "unknown"
    gpu_count: int = 0
    gpu_vram_gb: Optional[float] = None
    total_memory_gb: Optional[float] = None
    gpu_name: Optional[str] = None

    def to_dict(self) -> dict:
        return {
            "node": {
                "id": self.node_id,
                "name": self.node_name,
                "role": self.role,
                "secret": self.node_secret,
            },
            "supabase": {
                "url": self.supabase_url,
                "key": self.supabase_key,
            },
            "backend": {
                "url": (self.backend_url or get_default_backend_url()).rstrip("/"),
            },
            "inference": {
                "model": self.model,
                "model_path": self.model_path,
                "model_downloaded": self.model_downloaded,
            },
            "gpu": {
                "accelerator": self.accelerator,
                "count": self.gpu_count,
                "vram_gb": self.gpu_vram_gb if self.gpu_vram_gb is not None else 0.0,
                "total_memory_gb": self.total_memory_gb if self.total_memory_gb is not None else 0.0,
                "name": self.gpu_name or "",
            },
        }

    def gpu_info_payload(self) -> dict[str, object]:
        return {
            "accelerator": self.accelerator,
            "gpu_count": self.gpu_count,
            "gpu_name": self.gpu_name,
            "name": self.gpu_name,
            "gpu_vram_gb": self.gpu_vram_gb,
            "total_vram_gb": self.gpu_vram_gb,
            "vram_gb": self.gpu_vram_gb,
            "total_memory_gb": self.total_memory_gb,
            "model": self.model,
            "model_path": self.model_path,
            "model_downloaded": self.model_downloaded,
        }

    @classmethod
    def from_dict(cls, data: dict) -> NodeConfig:
        node = data.get("node", {})
        supa = data.get("supabase", {})
        backend = data.get("backend", {})
        inf = data.get("inference", {})
        gpu = data.get("gpu", {})
        return cls(
            node_id=node.get("id", ""),
            node_name=node.get("name", "default-node"),
            role=node.get("role", "both"),
            node_secret=node.get("secret", ""),
            supabase_url=supa.get("url", ""),
            supabase_key=supa.get("key", ""),
            backend_url=(backend.get("url") or get_default_backend_url()).rstrip("/"),
            model=inf.get("model", get_default_model_repo()),
            model_path=inf.get("model_path", ""),
            model_downloaded=inf.get("model_downloaded", False),
            accelerator=gpu.get("accelerator", "unknown"),
            gpu_count=gpu.get("count", 0),
            gpu_vram_gb=gpu.get("vram_gb"),
            total_memory_gb=gpu.get("total_memory_gb"),
            gpu_name=gpu.get("name"),
        )


def resolve_backend_url(explicit_url: str | None, config: NodeConfig | None = None) -> str:
    if explicit_url:
        return explicit_url.rstrip("/")
    if config and config.backend_url:
        return config.backend_url.rstrip("/")
    return get_default_backend_url()


def generate_node_id() -> str:
    return str(uuid.uuid4())


def save_config(config: NodeConfig) -> Path:
    RC_DIR.mkdir(parents=True, exist_ok=True)
    with open(CONFIG_PATH, "wb") as f:
        tomli_w.dump(config.to_dict(), f)
    return CONFIG_PATH


def load_config() -> NodeConfig:
    if not CONFIG_PATH.exists():
        raise FileNotFoundError(
            f"No config found at {CONFIG_PATH}. Run 'rc init' first."
        )
    with open(CONFIG_PATH, "rb") as f:
        data = tomllib.load(f)
    return NodeConfig.from_dict(data)
