"""
Goal-backward verification for phase completion.

Validates must-haves (truths, artifacts, key_links) against
phase goals before marking phase complete (EXEC-10, EXEC-11, EXEC-12).

Usage:
    from gsd_rlm.workflow.verification import (
        verify_phase_completion,
        load_must_haves_from_plan,
        MustHaves,
        VerificationResult,
    )

    must_haves = load_must_haves_from_plan(Path("05-04-PLAN.md"))
    result = verify_phase_completion(Path("phases/05-opencode"), must_haves)
    if result.passed:
        print("Phase verified!")
"""

import re
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Optional

import yaml


@dataclass
class MustHaves:
    """
    Required deliverables for phase completion.

    Captures the goal-backward verification criteria from PLAN.md
    frontmatter must_haves section.

    Attributes:
        truths: Observable behaviors that must be TRUE
        artifacts: Files that must exist with path, provides, exports
        key_links: Critical connections with from, to, via, pattern
    """

    truths: list[str] = field(default_factory=list)
    artifacts: list[dict[str, Any]] = field(default_factory=list)
    key_links: list[dict[str, Any]] = field(default_factory=list)

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "MustHaves":
        """Create MustHaves from dictionary."""
        return cls(
            truths=data.get("truths", []),
            artifacts=data.get("artifacts", []),
            key_links=data.get("key_links", []),
        )


@dataclass
class VerificationResult:
    """
    Result of phase completion verification.

    Contains pass/fail status and detailed breakdown of what
    was checked and any issues found.

    Attributes:
        passed: Whether all verification checks passed
        truths_checked: Number of truths enumerated
        artifacts_found: Number of artifacts that exist
        artifacts_missing: Number of artifacts not found
        key_links_valid: Number of valid key links
        key_links_broken: Number of broken key links
        details: Detailed messages about verification
        warnings: Non-fatal issues found during verification
    """

    passed: bool
    truths_checked: int = 0
    artifacts_found: int = 0
    artifacts_missing: int = 0
    key_links_valid: int = 0
    key_links_broken: int = 0
    details: list[str] = field(default_factory=list)
    warnings: list[str] = field(default_factory=list)

    def __str__(self) -> str:
        """Return string representation of result."""
        status = "PASSED" if self.passed else "FAILED"
        lines = [f"Verification: {status}"]
        lines.append(f"  Truths: {self.truths_checked} checked")
        lines.append(
            f"  Artifacts: {self.artifacts_found} found, "
            f"{self.artifacts_missing} missing"
        )
        lines.append(
            f"  Key Links: {self.key_links_valid} valid, {self.key_links_broken} broken"
        )
        if self.warnings:
            lines.append(f"  Warnings: {len(self.warnings)}")
        return "\n".join(lines)


def verify_phase_completion(
    phase_dir: Path,
    must_haves: MustHaves,
) -> VerificationResult:
    """
    Verify phase completion against must-haves.

    Checks artifacts (files must exist), key_links (connections
    must be valid), and enumerates truths (requires manual/test
    verification).

    Args:
        phase_dir: Path to phase directory
        must_haves: MustHaves instance with verification criteria

    Returns:
        VerificationResult with pass/fail status and details

    Example:
        >>> must_haves = MustHaves(
        ...     artifacts=[{"path": "src/module.py", "provides": "Feature"}]
        ... )
        >>> result = verify_phase_completion(Path("phases/05"), must_haves)
        >>> if result.passed:
        ...     print("Phase complete!")
    """
    details: list[str] = []
    warnings: list[str] = []
    artifacts_found = 0
    artifacts_missing = 0
    key_links_valid = 0
    key_links_broken = 0

    # Check artifacts (files must exist)
    for artifact in must_haves.artifacts:
        artifact_path = artifact.get("path", "")
        if not artifact_path:
            warnings.append("Artifact missing 'path' field")
            continue

        full_path = phase_dir / artifact_path

        if full_path.exists():
            artifacts_found += 1
            provides = artifact.get("provides", "unknown")
            details.append(f"✓ Artifact found: {artifact_path} ({provides})")

            # Check exports if specified
            exports = artifact.get("exports", [])
            if exports:
                content = full_path.read_text(encoding="utf-8")
                for export in exports:
                    if export in content:
                        details.append(f"  ✓ Export found: {export}")
                    else:
                        warnings.append(
                            f"Export '{export}' not found in {artifact_path}"
                        )
        else:
            artifacts_missing += 1
            provides = artifact.get("provides", "unknown")
            details.append(f"✗ Artifact missing: {artifact_path} ({provides})")

    # Check key_links (connections must be valid)
    for key_link in must_haves.key_links:
        from_path = key_link.get("from", "")
        if not from_path:
            warnings.append("Key link missing 'from' field")
            continue

        full_from_path = phase_dir / from_path

        if not full_from_path.exists():
            # Try relative to project root
            # (key_links may reference files outside phase_dir)
            key_links_broken += 1
            details.append(f"✗ Key link broken: {from_path} (file not found)")
            continue

        # Check pattern if specified
        pattern = key_link.get("pattern", "")
        if pattern:
            try:
                content = full_from_path.read_text(encoding="utf-8")
                if re.search(pattern, content):
                    key_links_valid += 1
                    via = key_link.get("via", "connection")
                    details.append(f"✓ Key link valid: {from_path} ({via})")
                else:
                    key_links_broken += 1
                    details.append(
                        f"✗ Key link broken: {from_path} "
                        f"(pattern '{pattern}' not found)"
                    )
            except re.error as e:
                key_links_broken += 1
                warnings.append(f"Invalid regex pattern '{pattern}': {e}")
        else:
            # No pattern specified, just check file exists
            key_links_valid += 1
            via = key_link.get("via", "connection")
            details.append(f"✓ Key link valid: {from_path} ({via})")

    # Enumerate truths (cannot auto-verify)
    for i, truth in enumerate(must_haves.truths, 1):
        details.append(f"? Truth #{i}: {truth} (requires verification)")

    # Determine pass/fail
    # Phase passes if no artifacts are missing and no key links are broken
    passed = artifacts_missing == 0 and key_links_broken == 0

    return VerificationResult(
        passed=passed,
        truths_checked=len(must_haves.truths),
        artifacts_found=artifacts_found,
        artifacts_missing=artifacts_missing,
        key_links_valid=key_links_valid,
        key_links_broken=key_links_broken,
        details=details,
        warnings=warnings,
    )


def load_must_haves_from_plan(plan_path: Path) -> MustHaves | None:
    """
    Load must-haves from PLAN.md frontmatter.

    Parses the YAML frontmatter from a PLAN.md file and extracts
    the must_haves section.

    Args:
        plan_path: Path to PLAN.md file

    Returns:
        MustHaves instance if found, None otherwise

    Example:
        >>> must_haves = load_must_haves_from_plan(
        ...     Path(".planning/phases/05-opencode/05-04-PLAN.md")
        ... )
        >>> if must_haves:
        ...     print(f"Found {len(must_haves.artifacts)} artifacts")
    """
    if not plan_path.exists():
        return None

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

    # Extract YAML frontmatter
    frontmatter_match = re.match(r"^---\s*\n(.*?)\n---", content, re.DOTALL)
    if not frontmatter_match:
        return None

    try:
        frontmatter = yaml.safe_load(frontmatter_match.group(1))
    except yaml.YAMLError:
        return None

    if not isinstance(frontmatter, dict):
        return None

    must_haves_data = frontmatter.get("must_haves")
    if not must_haves_data:
        return None

    return MustHaves.from_dict(must_haves_data)


def verify_artifact_exports(
    artifact_path: Path,
    exports: list[str],
) -> tuple[bool, list[str]]:
    """
    Verify that an artifact contains specified exports.

    Args:
        artifact_path: Path to the artifact file
        exports: List of export names to check for

    Returns:
        Tuple of (all_found, missing_exports)

    Example:
        >>> found, missing = verify_artifact_exports(
        ...     Path("src/module.py"),
        ...     ["ClassName", "function_name"]
        ... )
    """
    if not artifact_path.exists():
        return False, exports

    content = artifact_path.read_text(encoding="utf-8")
    missing = []

    for export in exports:
        # Check for class/function definition or variable assignment
        patterns = [
            rf"\bclass\s+{re.escape(export)}\b",
            rf"\bdef\s+{re.escape(export)}\b",
            rf"\basync\s+def\s+{re.escape(export)}\b",
            rf"^{re.escape(export)}\s*=",
            rf"\b{re.escape(export)}\s*:",
        ]

        found = any(re.search(p, content, re.MULTILINE) for p in patterns)
        if not found:
            missing.append(export)

    return len(missing) == 0, missing


def verify_key_link_pattern(
    source_path: Path,
    pattern: str,
) -> bool:
    """
    Verify that a key link pattern exists in source file.

    Args:
        source_path: Path to the source file
        pattern: Regex pattern to search for

    Returns:
        True if pattern found, False otherwise

    Example:
        >>> if verify_key_link_pattern(
        ...     Path("src/verification.py"),
        ...     r"yaml.*safe_load"
        ... ):
        ...     print("Pattern found!")
    """
    if not source_path.exists():
        return False

    try:
        content = source_path.read_text(encoding="utf-8")
        return bool(re.search(pattern, content))
    except (OSError, re.error):
        return False
