"""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: list[str] = field(default_factory=list)
    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"
    watch_issues_mode: str = "mine"
    cache_ttl: int = 300
    http_port: int = 8400
    _extra: dict = field(default_factory=dict, repr=False)


def save_config(path: Path, config: Config) -> None:
    """Atomic write of config to YAML, preserving unknown keys from the original file."""
    raw = dict(config._extra)  # start with unknown keys from the original load
    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,
        },
        "issues": {"mode": config.watch_issues_mode},
    }
    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 _parse_watch(raw: dict) -> dict:
    """Extract watch mode settings from raw config dict."""
    watch = raw.get("watch", {}) or {}
    mrs = watch.get("mrs", {}) or {}
    pipelines = watch.get("pipelines", {}) or {}
    vulns = watch.get("vulns", {}) or {}
    issues = watch.get("issues", {}) or {}
    return {
        "watch_mrs_mode": mrs.get("mode", "mine"),
        "watch_pipelines_mode": pipelines.get("mode", "mine"),
        "watch_vulns_mode": vulns.get("mode", "all"),
        "watch_vulns_min_severity": vulns.get("min_severity", "high"),
        "watch_issues_mode": issues.get("mode", "mine"),
    }


_KNOWN_KEYS = {"include", "exclude", "forges", "pull", "watch", "cache_ttl", "http_port"}


def _normalize_include(raw_include) -> list[str]:
    """Ensure include is a list (YAML might give a bare string)."""
    if isinstance(raw_include, str):
        return [raw_include]
    return raw_include or []


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 {}

    return Config(
        include=_normalize_include(raw.get("include")),
        exclude=raw.get("exclude") or [],
        forges=raw.get("forges") or {},
        pull_strategy=pull.get("strategy", "merge"),
        **_parse_watch(raw),
        cache_ttl=raw.get("cache_ttl", 300),
        http_port=raw.get("http_port", 8400),
        _extra={k: v for k, v in raw.items() if k not in _KNOWN_KEYS},
    )
