"""YAML configuration loading and saving for workspace settings."""

from __future__ import annotations

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

import yaml


@dataclass
class Config:
    """Workspace configuration with watch modes, forge settings, and defaults."""
    include: str | None = None
    exclude: list[str] = field(default_factory=list)
    forges: dict[str, dict] = field(default_factory=dict)
    pull_strategy: str = "merge"
    watch_mrs_mode: str = "mine"
    watch_pipelines_mode: str = "mine"
    watch_vulns_mode: str = "all"
    watch_vulns_min_severity: str = "high"
    cache_ttl: int = 300
    http_port: int = 8400


def save_config(path: Path, config: Config) -> None:
    """Atomic write of config to YAML."""
    raw = {}
    if config.include:
        raw["include"] = config.include
    if config.exclude:
        raw["exclude"] = config.exclude
    if config.forges:
        raw["forges"] = config.forges
    raw["pull"] = {"strategy": config.pull_strategy}
    raw["watch"] = {
        "mrs": {"mode": config.watch_mrs_mode},
        "pipelines": {"mode": config.watch_pipelines_mode},
        "vulns": {
            "mode": config.watch_vulns_mode,
            "min_severity": config.watch_vulns_min_severity,
        },
    }
    raw["cache_ttl"] = config.cache_ttl
    raw["http_port"] = config.http_port

    tmp = path.with_suffix(".tmp")
    tmp.write_text(yaml.dump(raw, default_flow_style=False))
    tmp.rename(path)


def load_config(path: Path) -> Config:
    """Load config from YAML file, returning defaults if the file is missing."""
    if not path.exists():
        return Config()

    try:
        raw = yaml.safe_load(path.read_text()) or {}
    except yaml.YAMLError as exc:
        sys.exit(f"project-hub: malformed config at {path}: {exc}")

    pull = raw.get("pull", {}) or {}
    watch = raw.get("watch", {}) or {}
    watch_mrs = watch.get("mrs", {}) or {}
    watch_pipelines = watch.get("pipelines", {}) or {}
    watch_vulns = watch.get("vulns", {}) or {}

    return Config(
        include=raw.get("include"),
        exclude=raw.get("exclude") or [],
        forges=raw.get("forges") or {},
        pull_strategy=pull.get("strategy", "merge"),
        watch_mrs_mode=watch_mrs.get("mode", "mine"),
        watch_pipelines_mode=watch_pipelines.get("mode", "mine"),
        watch_vulns_mode=watch_vulns.get("mode", "all"),
        watch_vulns_min_severity=watch_vulns.get("min_severity", "high"),
        cache_ttl=raw.get("cache_ttl", 300),
        http_port=raw.get("http_port", 8400),
    )
