"""Promote tripwire candidates to documentation frontmatter.

Writes tripwire entries into the YAML frontmatter of docs/learned/*.md files.
The tripwires.md index is regenerated by `erk docs sync` afterward.
"""

import logging
from dataclasses import dataclass
from pathlib import Path
from typing import Any, cast

import frontmatter
import yaml

logger = logging.getLogger(__name__)

_DOCS_LEARNED_DIR = "docs/learned"


@dataclass(frozen=True)
class PromotionResult:
    """Result of promoting a single tripwire to frontmatter.

    Attributes:
        success: Whether the promotion succeeded.
        target_doc_path: Relative doc path (e.g., "architecture/foo.md").
        error: Error message if promotion failed, None otherwise.
    """

    success: bool
    target_doc_path: str
    error: str | None


def _has_duplicate_action(tripwires: list[Any], action: str) -> bool:
    """Check if a tripwire with the given action already exists."""
    for entry in tripwires:
        if isinstance(entry, dict) and entry.get("action") == action:
            return True
    return False


def promote_tripwire_to_frontmatter(
    *,
    project_root: Path,
    target_doc_path: str,
    action: str,
    warning: str,
) -> PromotionResult:
    """Add a tripwire to a doc's YAML frontmatter.

    Reads the target doc file, adds a tripwire entry to its frontmatter
    `tripwires` list, and writes the file back. Skips if a tripwire with
    the same action string already exists (duplicate detection).

    Args:
        project_root: Project root directory containing docs/learned/.
        target_doc_path: Relative path within docs/learned/ (e.g., "architecture/foo.md").
        action: The action pattern to detect.
        warning: The warning message to display.

    Returns:
        PromotionResult with success status and any error.
    """
    full_path = project_root / _DOCS_LEARNED_DIR / target_doc_path

    if not full_path.exists():
        return PromotionResult(
            success=False,
            target_doc_path=target_doc_path,
            error=f"File not found: {_DOCS_LEARNED_DIR}/{target_doc_path}",
        )

    content = full_path.read_text(encoding="utf-8")

    # Check that content has frontmatter
    if not content.startswith("---"):
        return PromotionResult(
            success=False,
            target_doc_path=target_doc_path,
            error=f"No frontmatter found in {_DOCS_LEARNED_DIR}/{target_doc_path}",
        )

    try:
        post = frontmatter.loads(content)
    except (ValueError, yaml.YAMLError) as e:
        return PromotionResult(
            success=False,
            target_doc_path=target_doc_path,
            error=f"Failed to parse frontmatter: {e}",
        )

    if not isinstance(post.metadata, dict):
        return PromotionResult(
            success=False,
            target_doc_path=target_doc_path,
            error=f"Frontmatter is not a valid YAML mapping in "
            f"{_DOCS_LEARNED_DIR}/{target_doc_path}",
        )

    # Get or initialize tripwires list in metadata
    metadata: dict[str, Any] = post.metadata
    raw_tripwires = metadata.get("tripwires")

    if raw_tripwires is None:
        tripwires: list[Any] = []
        metadata["tripwires"] = tripwires
    elif not isinstance(raw_tripwires, list):
        return PromotionResult(
            success=False,
            target_doc_path=target_doc_path,
            error=f"tripwires key is not a list in {_DOCS_LEARNED_DIR}/{target_doc_path}",
        )
    else:
        tripwires = cast(list[Any], raw_tripwires)

    # Duplicate detection: check if same action already exists
    if _has_duplicate_action(tripwires, action):
        logger.debug(
            "Tripwire already exists for action %r in %s",
            action,
            target_doc_path,
        )
        return PromotionResult(
            success=True,
            target_doc_path=target_doc_path,
            error=None,
        )

    # Add the new tripwire entry
    tripwires.append({"action": action, "warning": warning})

    # Write back using frontmatter library
    full_path.write_text(frontmatter.dumps(post) + "\n", encoding="utf-8")

    return PromotionResult(
        success=True,
        target_doc_path=target_doc_path,
        error=None,
    )
