"""Framework registry: load framework_registry.yaml, lookup/search frameworks.

The registry YAML is bundled inside the ``complyform.profiles`` package
and loaded lazily on first access.
"""

from __future__ import annotations

from functools import lru_cache
from pathlib import Path

import yaml

from complyform.core.errors import ProfileBundleError, UnknownFrameworkError
from complyform.core.profiles.models import FrameworkMeta, FrameworkRegistry

_PROFILES_DIR = Path(__file__).resolve().parent.parent.parent / "profiles"


@lru_cache(maxsize=1)
def _load_registry() -> FrameworkRegistry:
    """Load and validate framework_registry.yaml (cached per process)."""
    path = _PROFILES_DIR / "framework_registry.yaml"
    if not path.exists():
        raise ProfileBundleError("framework_registry.yaml not found")
    raw = yaml.safe_load(path.read_text(encoding="utf-8"))
    try:
        return FrameworkRegistry.model_validate(raw)
    except Exception as exc:
        raise ProfileBundleError(str(exc)) from exc


def list_frameworks(
    *,
    tier: str | None = None,
    cloud: str | None = None,
    category: str | None = None,
) -> list[FrameworkMeta]:
    """Return all frameworks, optionally filtered."""
    reg = _load_registry()
    results = reg.frameworks
    if tier:
        results = [f for f in results if f.tier == tier]
    if cloud:
        results = [f for f in results if f.cloud in (cloud, "all")]
    if category:
        results = [f for f in results if f.category == category]
    return results


def get_framework(framework_id: str) -> FrameworkMeta:
    """Get a single framework by ID. Raises UnknownFrameworkError."""
    reg = _load_registry()
    for fw in reg.frameworks:
        if fw.id == framework_id:
            return fw
    valid_ids = [fw.id for fw in reg.frameworks]
    raise UnknownFrameworkError([framework_id], valid_ids)


def search_frameworks(query: str) -> list[FrameworkMeta]:
    """Search frameworks by name or ID (case-insensitive substring)."""
    reg = _load_registry()
    q = query.lower()
    return [f for f in reg.frameworks if q in f.id.lower() or q in f.name.lower()]


def _reset_cache() -> None:
    """Clear cached registry — for testing only."""
    _load_registry.cache_clear()
