"""Load and validate YAML rule catalogs."""

from __future__ import annotations

from pathlib import Path
from typing import Any, Dict, List, Optional

import yaml


_RULES_DIR = Path(__file__).parent

_VALID_SEVERITIES = {"FAIL", "WARN", "INFO"}


def _load_yaml_file(filename: str) -> Dict[str, Any]:
    """Load a single YAML rule file from the rules directory."""
    path = _RULES_DIR / filename
    if not path.exists():
        return {}
    with open(path, "r") as f:
        return yaml.safe_load(f) or {}


def load_rules(platform: str) -> List[Dict[str, Any]]:
    """Load all rules for a given platform from its YAML catalog.

    Returns a flat list of rule dicts with keys: id, summary, severity, fix, reference, detection.
    """
    filename_map = {
        "ios": "ios_rules.yaml",
        "android": "android_rules.yaml",
        "web": "web_rules.yaml",
        "common": "common_rules.yaml",
    }
    filename = filename_map.get(platform)
    if not filename:
        return []

    data = _load_yaml_file(filename)
    categories = data.get("categories", [])

    rules: List[Dict[str, Any]] = []
    for category in categories:
        for rule in category.get("rules", []):
            rules.append(rule)

    return rules


def get_rule_ids(platform: str) -> List[str]:
    """Return all rule IDs for a given platform."""
    return [r["id"] for r in load_rules(platform)]


def get_rule_by_id(platform: str, rule_id: str) -> Optional[Dict[str, Any]]:
    """Look up a single rule by its ID."""
    for rule in load_rules(platform):
        if rule["id"] == rule_id:
            return rule
    return None


def validate_rules(platform: str) -> List[str]:
    """Validate rule catalog structure. Returns list of error messages."""
    errors: List[str] = []
    rules = load_rules(platform)

    seen_ids: set = set()
    for rule in rules:
        rid = rule.get("id", "")
        if not rid:
            errors.append("Rule missing 'id' field")
            continue

        if rid in seen_ids:
            errors.append(f"Duplicate rule ID: {rid}")
        seen_ids.add(rid)

        if rule.get("severity") not in _VALID_SEVERITIES:
            errors.append(f"{rid}: Invalid severity '{rule.get('severity')}'")
        if not rule.get("summary"):
            errors.append(f"{rid}: Missing 'summary'")
        if not rule.get("fix"):
            errors.append(f"{rid}: Missing 'fix'")

    return errors
