"""
Handler for /gsd-rlm-execute-phase command.

This module provides the execute_phase_command handler that runs
wave-based execution for plans in a phase using HybridOrchestrator.

Requirements: INT-04 (execute-phase command), INT-05 (orchestrator entry)
"""

from __future__ import annotations

import logging
import re
from pathlib import Path
from typing import Any

from gsd_rlm.commands.router import CommandConfig, CommandResult
from gsd_rlm.execution.dependency import DependencyGraph
from gsd_rlm.execution.parallel import WaveRunner
from gsd_rlm.coordination.orchestrator import HybridOrchestrator, WaveResult

logger = logging.getLogger(__name__)


def _discover_plans(phase_dir: Path) -> list[dict[str, Any]]:
    """Discover PLAN.md files in a phase directory.

    Args:
        phase_dir: Path to phase directory

    Returns:
        List of plan dictionaries with id, path, and dependencies
    """
    plans = []

    if not phase_dir.exists():
        return plans

    for plan_file in sorted(phase_dir.glob("*-PLAN.md")):
        plan_id = plan_file.stem.replace("-PLAN", "")
        content = plan_file.read_text(encoding="utf-8")

        # Parse depends_on from frontmatter
        deps = _parse_dependencies(content)

        plans.append(
            {
                "id": plan_id,
                "path": str(plan_file),
                "depends_on": deps,
            }
        )

    return plans


def _parse_dependencies(plan_content: str) -> list[str]:
    """Parse depends_on from PLAN.md frontmatter.

    Args:
        plan_content: Content of PLAN.md file

    Returns:
        List of plan IDs this plan depends on
    """
    deps = []

    # Look for depends_on in frontmatter
    deps_match = re.search(r"depends_on:\s*\n(\s+-\s+.+\n)+", plan_content)
    if deps_match:
        for line in deps_match.group(0).split("\n"):
            dep_match = re.match(r"\s+-\s+(\S+)", line)
            if dep_match:
                deps.append(dep_match.group(1))

    return deps


def _build_dependency_graph(plans: list[dict[str, Any]]) -> DependencyGraph:
    """Build dependency graph from plan list.

    Args:
        plans: List of plan dictionaries

    Returns:
        DependencyGraph instance
    """
    graph = DependencyGraph()

    for plan in plans:
        graph.add_task(plan["id"], depends_on=plan["depends_on"] or None)

    return graph


async def execute_phase_command(config: CommandConfig) -> CommandResult:
    """Execute plans in a phase with wave-based parallelization.

    Loads phase directory, discovers plans, builds dependency graph,
    and executes using HybridOrchestrator.

    Args:
        config: Command configuration with:
            - args["phase"]: Phase number (1-indexed)
            - args["max_concurrent"]: Max concurrent plans (default: 10)
            - project_dir: Project directory with .planning/

    Returns:
        CommandResult with success status and wave results
    """
    try:
        project_dir = config.project_dir
        planning_dir = project_dir / ".planning"
        phases_dir = planning_dir / "phases"

        # Get phase number
        phase_num = config.args.get("phase", 1)
        max_concurrent = config.args.get("max_concurrent", 10)

        # Find phase directory
        phase_dirs = list(phases_dir.glob(f"{phase_num:02d}-*"))
        if not phase_dirs:
            return CommandResult(
                success=False,
                message=f"Phase {phase_num} directory not found",
                error=f"No phase directory matching {phase_num:02d}-*",
            )

        phase_dir = phase_dirs[0]
        logger.info(f"Executing phase from: {phase_dir}")

        # Discover plans
        plans = _discover_plans(phase_dir)
        if not plans:
            return CommandResult(
                success=False,
                message=f"No plans found in phase {phase_num}",
                error="No PLAN.md files found",
            )

        logger.info(f"Found {len(plans)} plans: {[p['id'] for p in plans]}")

        # Build dependency graph
        graph = _build_dependency_graph(plans)

        # Validate graph for cycles
        try:
            graph.validate()
        except ValueError as e:
            return CommandResult(
                success=False,
                message=f"Circular dependency detected: {e}",
                error=str(e),
            )

        # Get waves
        waves = graph.get_waves()
        logger.info(f"Execution waves: {waves}")

        # Create executor function
        async def execute_plan(plan_id: str) -> dict[str, Any]:
            """Execute a single plan."""
            plan = next((p for p in plans if p["id"] == plan_id), None)
            if not plan:
                raise ValueError(f"Plan {plan_id} not found")

            # In a real implementation, this would invoke the planner skill
            # and execute the plan's tasks
            logger.info(f"Executing plan: {plan_id}")

            # Simulate execution
            return {
                "plan_id": plan_id,
                "status": "completed",
                "tasks_executed": 1,
            }

        # Create wave runner and orchestrator
        wave_runner = WaveRunner(max_concurrent=max_concurrent)
        orchestrator = HybridOrchestrator(graph, wave_runner)

        # Progress callback
        wave_results = []

        def on_wave_complete(result: WaveResult) -> None:
            wave_results.append(result)
            logger.info(
                f"Wave {result.wave_id} complete: "
                f"{len(result.results)} succeeded, {len(result.errors)} failed"
            )

        # Execute
        results = await orchestrator.execute(
            executor=execute_plan,
            on_wave_complete=on_wave_complete,
        )

        # Calculate summary
        total_succeeded = sum(len(r.results) for r in results)
        total_failed = sum(len(r.errors) for r in results)

        success = total_failed == 0

        return CommandResult(
            success=success,
            message=f"Executed phase {phase_num}: {total_succeeded} plans succeeded, {total_failed} failed",
            data={
                "phase_number": phase_num,
                "total_plans": len(plans),
                "waves_executed": len(results),
                "plans_succeeded": total_succeeded,
                "plans_failed": total_failed,
                "wave_results": [
                    {
                        "wave_id": r.wave_id,
                        "task_ids": r.task_ids,
                        "success": r.success,
                    }
                    for r in results
                ],
            },
        )

    except Exception as e:
        logger.exception(f"Failed to execute phase: {e}")
        return CommandResult(
            success=False,
            message=f"Failed to execute phase: {e}",
            error=str(e),
        )
