"""Scout YAML loader."""

from __future__ import annotations

from pathlib import Path
from typing import Any

try:
    import yaml
except Exception as exc:  # pragma: no cover - handled at runtime
    raise RuntimeError("PyYAML is required for scout definitions.") from exc

from .models import ScanConfig, ScoutDefinition

from g_gremlin.config import get_config_dir as _get_config_dir
from g_gremlin.paths import gremlin_path

DEFAULT_SCOUTS_DIR = _get_config_dir() / "scouts"
USER_SCOUTS_DIR = gremlin_path("scouts")
SCAN_DEFAULTS_FILE = "_scan_defaults.yaml"


class ScoutLoader:
    """Loads and manages Scout definitions from YAML."""

    def __init__(
        self,
        scout_dirs: list[Path] | None = None,
        user_credentials: set[str] | None = None,
    ) -> None:
        self.scout_dirs = scout_dirs or [DEFAULT_SCOUTS_DIR, USER_SCOUTS_DIR]
        self.user_credentials = user_credentials or set()
        self._scouts: dict[str, ScoutDefinition] = {}
        self._load_all()

    def _load_all(self) -> None:
        for scout_dir in self.scout_dirs:
            if not scout_dir.exists():
                continue
            for yaml_file in scout_dir.glob("*.yaml"):
                if yaml_file.name.startswith("_"):
                    continue
                try:
                    scout = self._load_scout(yaml_file)
                    if scout:
                        self._scouts[scout.name] = scout
                except Exception:
                    continue

    def _load_scout(self, path: Path) -> ScoutDefinition | None:
        with path.open(encoding="utf-8") as handle:
            data = yaml.safe_load(handle)

        if not data or not data.get("name"):
            return None

        return ScoutDefinition.from_dict(data)

    def get_scout(self, name: str) -> ScoutDefinition | None:
        return self._scouts.get(name)

    def list_scouts(self) -> list[ScoutDefinition]:
        return list(self._scouts.values())

    def reload(self) -> None:
        self._scouts.clear()
        self._load_all()


def _load_yaml(path: Path) -> dict[str, Any]:
    if not path.exists():
        return {}
    with path.open(encoding="utf-8") as handle:
        data = yaml.safe_load(handle)
    return data or {}


def load_scan_config(config_path: Path | None = None) -> ScanConfig:
    """
    Load scan configuration. If config_path is None, load defaults and apply
    user overrides from ~/.g_gremlin/scouts/_scan_defaults.yaml when present.
    """
    if config_path:
        return ScanConfig.from_dict(_load_yaml(config_path))

    base = ScanConfig.from_dict(_load_yaml(DEFAULT_SCOUTS_DIR / SCAN_DEFAULTS_FILE))
    user_override_path = USER_SCOUTS_DIR / SCAN_DEFAULTS_FILE
    if user_override_path.exists():
        override_data = _load_yaml(user_override_path)
        merged = base.to_dict()
        merged.update({k: v for k, v in override_data.items() if v is not None})
        return ScanConfig.from_dict(merged)
    return base


__all__ = [
    "DEFAULT_SCOUTS_DIR",
    "USER_SCOUTS_DIR",
    "SCAN_DEFAULTS_FILE",
    "ScoutLoader",
    "load_scan_config",
]
