"""
Spec loader for ROADMAP and REQUIREMENTS files.

Provides structured access to planning specifications for
spec-driven workflow execution (EXEC-10, EXEC-11, EXEC-12).

Usage:
    from gsd_rlm.workflow.spec_loader import SpecLoader, load_roadmap

    loader = SpecLoader(Path(".planning"))
    roadmap = loader.load_roadmap()
    phase = loader.get_phase("05")
"""

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


@dataclass
class PhaseSpec:
    """Specification for a single phase from ROADMAP.md."""

    number: str  # Phase number (e.g., "05")
    name: str  # Phase name
    goal: str  # Phase goal
    requirements: list[str] = field(default_factory=list)  # Requirement IDs
    success_criteria: list[str] = field(default_factory=list)  # Success criteria
    depends_on: list[str] = field(default_factory=list)  # Dependencies
    plans: list[str] = field(default_factory=list)  # Plan files
    status: str = "not_started"  # not_started, in_progress, complete

    def __post_init__(self):
        """Ensure lists are initialized."""
        if self.requirements is None:
            self.requirements = []
        if self.success_criteria is None:
            self.success_criteria = []
        if self.depends_on is None:
            self.depends_on = []
        if self.plans is None:
            self.plans = []


class SpecLoader:
    """
    Loader for ROADMAP.md and REQUIREMENTS.md files.

    Parses planning specification files into structured data
    for spec-driven workflow execution.

    Attributes:
        planning_dir: Path to .planning directory
        roadmap: Parsed ROADMAP.md content
        requirements: Parsed REQUIREMENTS.md content

    Example:
        >>> loader = SpecLoader(Path(".planning"))
        >>> roadmap = loader.load_roadmap()
        >>> phase = loader.get_phase("01")
        >>> print(phase.name)
        "Core Workflow Foundation"
    """

    def __init__(self, planning_dir: Path):
        """
        Initialize SpecLoader.

        Args:
            planning_dir: Path to .planning directory
        """
        self.planning_dir = Path(planning_dir)
        self._roadmap: dict[str, Any] | None = None
        self._requirements: dict[str, Any] | None = None
        self._phases: dict[str, PhaseSpec] = {}

    @property
    def roadmap(self) -> dict[str, Any] | None:
        """Get parsed ROADMAP.md content."""
        return self._roadmap

    @property
    def requirements(self) -> dict[str, Any] | None:
        """Get parsed REQUIREMENTS.md content."""
        return self._requirements

    def load_roadmap(self) -> dict[str, Any]:
        """
        Load and parse ROADMAP.md.

        Returns:
            Dictionary with phases, progress, and metadata

        Raises:
            FileNotFoundError: If ROADMAP.md doesn't exist
        """
        roadmap_path = self.planning_dir / "ROADMAP.md"
        if not roadmap_path.exists():
            raise FileNotFoundError(f"ROADMAP.md not found at {roadmap_path}")

        content = roadmap_path.read_text(encoding="utf-8")
        self._roadmap = self._parse_roadmap(content)
        self._build_phases()
        return self._roadmap

    def load_requirements(self) -> dict[str, Any]:
        """
        Load and parse REQUIREMENTS.md.

        Returns:
            Dictionary with requirements, traceability, and metadata

        Raises:
            FileNotFoundError: If REQUIREMENTS.md doesn't exist
        """
        requirements_path = self.planning_dir / "REQUIREMENTS.md"
        if not requirements_path.exists():
            raise FileNotFoundError(f"REQUIREMENTS.md not found at {requirements_path}")

        content = requirements_path.read_text(encoding="utf-8")
        self._requirements = self._parse_requirements(content)
        return self._requirements

    def get_phase(self, phase_number: str) -> PhaseSpec | None:
        """
        Get phase specification by number.

        Args:
            phase_number: Phase number (e.g., "05" or "5")

        Returns:
            PhaseSpec if found, None otherwise
        """
        # Normalize phase number
        normalized = phase_number.zfill(2)
        return self._phases.get(normalized)

    def list_phases(self) -> list[str]:
        """
        List all phase numbers.

        Returns:
            List of phase numbers in order
        """
        return sorted(self._phases.keys())

    def _parse_roadmap(self, content: str) -> dict[str, Any]:
        """
        Parse ROADMAP.md content.

        Args:
            content: Raw ROADMAP.md content

        Returns:
            Parsed structure with phases and progress
        """
        result: dict[str, Any] = {
            "overview": "",
            "phases": {},
            "progress": {},
        }

        lines = content.split("\n")

        # Extract overview (first paragraph after title)
        in_overview = False
        overview_lines = []
        for line in lines:
            if line.startswith("# "):
                in_overview = True
                continue
            if in_overview:
                if line.startswith("## "):
                    break
                if line.strip():
                    overview_lines.append(line.strip())
        result["overview"] = " ".join(overview_lines)

        # Parse phase sections
        current_phase = None
        current_section = None

        for line in lines:
            # Match "### Phase N: Name"
            phase_match = re.match(r"###\s+Phase\s+(\d+(?:\.\d+)?):?\s*(.+)", line)
            if phase_match:
                phase_num = phase_match.group(1).zfill(2)
                phase_name = phase_match.group(2).strip()
                current_phase = phase_num
                result["phases"][current_phase] = {
                    "number": phase_num,
                    "name": phase_name,
                    "goal": "",
                    "requirements": [],
                    "success_criteria": [],
                    "depends_on": [],
                    "plans": [],
                }
                continue

            if current_phase:
                phase_data = result["phases"][current_phase]

                # Parse **Goal**:
                if line.startswith("**Goal**:"):
                    phase_data["goal"] = line.replace("**Goal**:", "").strip()

                # Parse **Depends on**:
                elif line.startswith("**Depends on**:"):
                    deps = line.replace("**Depends on**:", "").strip()
                    # Handle "Nothing", "Nothing (first phase)", etc.
                    if deps and not deps.lower().startswith("nothing"):
                        phase_data["depends_on"] = [
                            d.strip() for d in deps.split(",") if d.strip()
                        ]

                # Parse **Requirements**:
                elif line.startswith("**Requirements**:"):
                    reqs = line.replace("**Requirements**:", "").strip()
                    phase_data["requirements"] = [
                        r.strip() for r in reqs.split(",") if r.strip()
                    ]

                # Parse success criteria (numbered list)
                elif re.match(r"\s*\d+\.", line):
                    criterion = re.sub(r"^\s*\d+\.\s*", "", line).strip()
                    if criterion:
                        phase_data["success_criteria"].append(criterion)

                # Parse plans list items
                elif line.strip().startswith("- ["):
                    plan_match = re.search(r"(\d{2}-\d{2}-PLAN\.md)", line)
                    if plan_match:
                        phase_data["plans"].append(plan_match.group(1))

        return result

    def _parse_requirements(self, content: str) -> dict[str, Any]:
        """
        Parse REQUIREMENTS.md content.

        Args:
            content: Raw REQUIREMENTS.md content

        Returns:
            Parsed structure with requirements and traceability
        """
        result: dict[str, Any] = {
            "core_value": "",
            "requirements": {},
            "traceability": {},
        }

        lines = content.split("\n")

        # Extract core value
        for line in lines:
            if line.startswith("**Core Value:**"):
                result["core_value"] = line.replace("**Core Value:**", "").strip()
                break

        # Parse requirements
        current_req = None
        for line in lines:
            # Match requirement checkbox: - [x] **REQ-ID**: description
            req_match = re.match(r"-\s*\[([ x])\]\s*\*\*([A-Z]+-\d+)\*\*:\s*(.+)", line)
            if req_match:
                checked = req_match.group(1) == "x"
                req_id = req_match.group(2)
                description = req_match.group(3).strip()
                current_req = req_id
                result["requirements"][req_id] = {
                    "id": req_id,
                    "description": description,
                    "complete": checked,
                    "phase": None,
                }

        # Parse traceability table
        in_traceability = False
        for line in lines:
            if "## Traceability" in line:
                in_traceability = True
                continue
            if in_traceability:
                # Skip headers and separators
                if line.startswith("|--") or line.startswith("| Requirement"):
                    continue
                # Parse table row
                if line.startswith("|"):
                    parts = [p.strip() for p in line.split("|")]
                    parts = [p for p in parts if p]  # Remove empty
                    if len(parts) >= 3:
                        req_id = parts[0]
                        phase = parts[1]
                        status = parts[2]
                        if req_id in result["requirements"]:
                            result["requirements"][req_id]["phase"] = phase
                            result["requirements"][req_id]["status"] = status
                        result["traceability"][req_id] = {
                            "phase": phase,
                            "status": status,
                        }

        return result

    def _build_phases(self) -> None:
        """Build PhaseSpec objects from parsed roadmap."""
        if not self._roadmap:
            return

        for phase_num, phase_data in self._roadmap.get("phases", {}).items():
            spec = PhaseSpec(
                number=phase_num,
                name=phase_data.get("name", ""),
                goal=phase_data.get("goal", ""),
                requirements=phase_data.get("requirements", []),
                success_criteria=phase_data.get("success_criteria", []),
                depends_on=phase_data.get("depends_on", []),
                plans=phase_data.get("plans", []),
            )
            self._phases[phase_num] = spec


# Convenience functions


def load_roadmap(planning_dir: Path) -> dict[str, Any]:
    """
    Load ROADMAP.md from planning directory.

    Args:
        planning_dir: Path to .planning directory

    Returns:
        Parsed roadmap dictionary

    Example:
        >>> roadmap = load_roadmap(Path(".planning"))
        >>> print(roadmap["phases"]["01"]["name"])
        "Core Workflow Foundation"
    """
    loader = SpecLoader(planning_dir)
    return loader.load_roadmap()


def load_requirements(planning_dir: Path) -> dict[str, Any]:
    """
    Load REQUIREMENTS.md from planning directory.

    Args:
        planning_dir: Path to .planning directory

    Returns:
        Parsed requirements dictionary

    Example:
        >>> reqs = load_requirements(Path(".planning"))
        >>> print(reqs["requirements"]["AGENT-01"]["description"])
        "User can define agents with name, role, goal, backstory, and tools"
    """
    loader = SpecLoader(planning_dir)
    return loader.load_requirements()
