"""Trigger cache for procedure advisor hook.

Generates and loads a YAML file containing L1 and L2-tier procedures with
their tool triggers and context patterns. The hook script reads this file
instead of querying the database (hook timeout is ~2s, DB access is risky).

L2 procedures with tool triggers are included because they are mature
(5+ successes, 75%+ confidence) and warrant preemptive advisory.

Cache is regenerated by:
- seed_procedures.py (initial population)
- promoter.py (on tier changes)
"""

from __future__ import annotations

import json
import logging
import os
import tempfile
from pathlib import Path

import yaml

logger = logging.getLogger(__name__)

_CACHE_PATH = Path(__file__).resolve().parents[4] / "config" / "procedure_triggers.yaml"


def get_cache_path() -> Path:
    return _CACHE_PATH


async def regenerate(db: object) -> int:
    """Regenerate trigger cache from L1+L2 procedures in the database.

    Uses atomic write (temp file + rename) to avoid race conditions
    with the hook reading the file.

    Returns the number of triggers written.
    """
    from genesis.db.crud import procedural

    # Include both L1 and L2 procedures — L2 with tool triggers are mature
    # enough (5+ successes, 75%+ confidence) to warrant hook advisories.
    rows_l1 = await procedural.list_by_tier(db, "L1")  # type: ignore[arg-type]
    rows_l2 = await procedural.list_by_tier(db, "L2")  # type: ignore[arg-type]
    rows = rows_l1 + rows_l2
    triggers = []
    for row in rows:
        tool_trigger = json.loads(row["tool_trigger"]) if row.get("tool_trigger") else None
        if not tool_trigger:
            continue

        # Build context patterns from context_tags for regex matching
        context_patterns = json.loads(row["context_tags"]) if isinstance(row["context_tags"], str) else row["context_tags"]

        triggers.append({
            "tool": tool_trigger,
            "context_patterns": context_patterns,
            "procedure_id": row["id"],
            "task_type": row["task_type"],
            "principle": row["principle"],
            "steps": json.loads(row["steps"]) if isinstance(row["steps"], str) else row["steps"],
            "confidence": row["confidence"],
        })

    cache_data = {
        "generated_at": __import__("datetime").datetime.now(__import__("datetime").UTC).isoformat(),
        "triggers": triggers,
    }

    # Atomic write: temp file + rename
    _CACHE_PATH.parent.mkdir(parents=True, exist_ok=True)
    fd, tmp_path = tempfile.mkstemp(dir=_CACHE_PATH.parent, suffix=".tmp")
    try:
        with os.fdopen(fd, "w") as f:
            yaml.dump(cache_data, f, default_flow_style=False, sort_keys=False)
        os.rename(tmp_path, str(_CACHE_PATH))
    except Exception:
        # Clean up temp file on failure
        with __import__("contextlib").suppress(OSError):
            os.unlink(tmp_path)
        raise

    logger.info("Regenerated procedure trigger cache: %d triggers", len(triggers))
    return len(triggers)


def load() -> list[dict]:
    """Load triggers from YAML cache. Returns empty list on any error."""
    try:
        data = yaml.safe_load(_CACHE_PATH.read_text())
        return data.get("triggers", []) if data else []
    except Exception:
        return []
