#!/usr/bin/env python3
"""
utils/event_hooks_loader.py — 훅 디렉토리 탐색 및 동적 로드

HOOK.yaml + handler.py 기반 훅을 파일시스템에서 발견하여
HookRegistry에 등록한다.

Usage:
    from utils.event_hooks_loader import discover_hooks

    discover_hooks(registry, "/path/to/hooks_dir")
"""

from __future__ import annotations

import importlib.util
import sys
from pathlib import Path
from typing import TYPE_CHECKING, Any

import yaml

from utils.logger import get_logger

if TYPE_CHECKING:
    from utils.event_hooks import HookRegistry

logger = get_logger(__name__)


def discover_hooks(registry: "HookRegistry", hooks_dir: str) -> None:
    """디렉토리를 순회하여 HOOK.yaml + handler.py 기반 훅을 동적으로 로드한다.

    각 서브디렉토리에서 다음을 기대한다:
      HOOK.yaml  — 최소 ``event`` 키 (와일드카드 포함 가능), 선택 ``name``
      handler.py — ``handle(ctx)`` 함수 정의

    오류(파일 없음, 파싱 실패, 임포트 실패 등)는 log 후 건너뜀.

    Args:
        registry: 핸들러를 등록할 HookRegistry 인스턴스
        hooks_dir: 훅 서브디렉토리들이 위치한 상위 디렉토리 경로
    """
    base = Path(hooks_dir)
    if not base.is_dir():
        logger.debug("discover_hooks: directory does not exist: %s", hooks_dir)
        return

    for hook_dir in sorted(base.iterdir()):
        if not hook_dir.is_dir():
            continue

        yaml_path = hook_dir / "HOOK.yaml"
        handler_path = hook_dir / "handler.py"

        if not yaml_path.exists():
            logger.debug("discover_hooks: skipping '%s' (no HOOK.yaml)", hook_dir.name)
            continue
        if not handler_path.exists():
            logger.debug("discover_hooks: skipping '%s' (no handler.py)", hook_dir.name)
            continue

        try:
            meta: dict[str, Any] = yaml.safe_load(yaml_path.read_text(encoding="utf-8")) or {}
        except Exception as exc:  # noqa: BLE001
            logger.warning("discover_hooks: failed to parse HOOK.yaml in '%s': %s", hook_dir.name, exc)
            continue

        event_type: str = meta.get("event", "")
        if not event_type:
            logger.warning("discover_hooks: '%s' HOOK.yaml missing 'event' key", hook_dir.name)
            continue

        hook_name: str = meta.get("name", hook_dir.name)

        try:
            module_name = f"_hook_{hook_dir.name}"
            spec = importlib.util.spec_from_file_location(module_name, handler_path)
            if spec is None or spec.loader is None:
                raise ImportError(f"Cannot load spec from {handler_path}")
            module = importlib.util.module_from_spec(spec)
            sys.modules[module_name] = module
            spec.loader.exec_module(module)  # type: ignore[union-attr]
            handler_fn = getattr(module, "handle", None)
            if handler_fn is None:
                raise AttributeError(f"handler.py in '{hook_dir.name}' has no 'handle' function")
            registry.register(event_type, handler_fn, name=hook_name)
            logger.info("discover_hooks: loaded hook '%s' for event '%s'", hook_name, event_type)
        except Exception as exc:  # noqa: BLE001
            logger.warning("discover_hooks: failed to load hook in '%s': %s", hook_dir.name, exc)
