"""Run command - Execute phase/step of LAIDA.

Contract: CNT-T4-CMD-002
Traceability: UC-022, UX-001, UI-002
"""

from pathlib import Path

import click
from rich.progress import Progress, SpinnerColumn, TextColumn

from laida_cli.adapters.claude_code_adapter import ClaudeCodeSubprocessAdapter
from laida_cli.ports.claude_code_port import ClaudeCodeAuthError
from laida_cli.services.context_validator import ContextValidator
from laida_cli.services.detect_state import DetectStateService
from laida_cli.services.execute_phase import ExecutePhaseService
from laida_cli.ui import LaidaConsole, StreamingPanel

console = LaidaConsole()


@click.command("run")
@click.argument("phase", type=click.IntRange(0, 4))
@click.argument("step", type=click.IntRange(0, 3))
@click.option(
    "--path", "-p",
    type=click.Path(exists=True),
    default=".",
    help="Path to LAIDA project (default: current directory)",
)
@click.option(
    "--verbose", "-v",
    is_flag=True,
    help="Show verbose output",
)
@click.option(
    "--skip-validation",
    is_flag=True,
    help="Skip project validation before execution",
)
@click.option(
    "--dry-run",
    is_flag=True,
    help="Show what would be executed without running",
)
@click.option(
    "--stream/--no-stream",
    default=True,
    help="Stream output in real-time (default: enabled)",
)
def run_command(
    phase: int,
    step: int,
    path: str,
    verbose: bool,
    skip_validation: bool,
    dry_run: bool,
    stream: bool,
) -> None:
    """Execute a specific phase and step.

    PHASE: Phase number (0-4)
    STEP: Step number (0-3)

    Examples:
        laida run 0 0  # Execute Phase 0 Step 0
        laida run 1 2  # Execute Phase 1 Step 2
    """
    project_path = Path(path).resolve()

    # Check if LAIDA project
    if not (project_path / ".laida").exists():
        console.error("Not a LAIDA project. Run 'laida init' first.")
        raise SystemExit(1)

    # Get step name
    state_service = DetectStateService()
    step_name = state_service.get_step_name(phase, step)

    console.phase_header(phase, step, step_name)
    console.print(f"Path: {project_path}")
    console.print()

    # Validate project state
    if not skip_validation and not _validate_prerequisites(project_path, phase, step):
        raise SystemExit(1)

    # Dry run mode
    if dry_run:
        console.warning("Dry run mode - no changes will be made", prefix="")
        console.print()
        _show_execution_plan(project_path, phase, step)
        return

    # Create adapter and service
    claude_adapter = ClaudeCodeSubprocessAdapter()
    execute_service = ExecutePhaseService(claude_adapter)

    try:
        # Execute with streaming or blocking mode
        if stream:
            # Streaming mode: real-time output display
            streaming_panel = StreamingPanel(console=console)

            with streaming_panel.live_output(
                title=f"Phase {phase} Step {step}: {step_name}"
            ) as on_output:
                result = execute_service.execute_streaming(
                    phase=phase,
                    step=step,
                    project_path=str(project_path),
                    on_output=on_output,
                )
        else:
            # Blocking mode: spinner only
            with Progress(
                SpinnerColumn(),
                TextColumn("[progress.description]{task.description}"),
                console=console,
            ) as progress:
                task = progress.add_task(
                    f"Executing Phase {phase} Step {step}...",
                    total=None,
                )

                result = execute_service.execute(
                    phase=phase,
                    step=step,
                    project_path=str(project_path),
                )

                progress.update(task, completed=True)

    except ClaudeCodeAuthError as e:
        console.print()
        console.error("Not authenticated with Claude Code")
        console.print()
        console.muted(f"Details: {e}")
        console.print()
        console.hint("Run 'laida login' to authenticate, then try again.")
        raise SystemExit(1) from None

    # Display result
    console.print()
    if result.success:
        console.success("Success!")
        console.muted(f"Output files: {len(result.output_files)}")

        if verbose and result.output_files:
            for f in result.output_files[:10]:
                console.muted(f"  - {f}")
    else:
        console.error("Failed!")
        console.print(f"Error: {result.error_message}")
        raise SystemExit(1)


def _validate_prerequisites(project_path: Path, phase: int, step: int) -> bool:
    """Validate prerequisites for execution.

    Args:
        project_path: Path to project
        phase: Phase number
        step: Step number

    Returns:
        True if prerequisites are met
    """
    # Validate context for Phase 0
    if phase == 0:
        validator = ContextValidator()
        result = validator.validate(project_path)

        if not result.is_valid:
            console.error("Invalid project_context.yaml")
            for error in result.errors:
                console.muted(f"  - {error}")
            return False

    # Check if previous step completed (unless first step)
    state_service = DetectStateService()
    state = state_service.detect(project_path)

    expected_phase = state.next_phase
    expected_step = state.next_step

    if phase < expected_phase or (phase == expected_phase and step < expected_step):
        console.warning(
            f"Step {phase}.{step} already completed. Re-running may overwrite existing outputs."
        )

    if phase > expected_phase or (phase == expected_phase and step > expected_step):
        console.error(
            f"Cannot run Phase {phase} Step {step}. "
            f"Next expected: Phase {expected_phase} Step {expected_step}"
        )
        return False

    return True


def _show_execution_plan(project_path: Path, phase: int, step: int) -> None:  # noqa: ARG001
    """Show what would be executed.

    Args:
        project_path: Path to project
        phase: Phase number
        step: Step number
    """
    state_service = DetectStateService()
    step_name = state_service.get_step_name(phase, step)

    console.header("Execution Plan")
    console.muted("  1. Clear Claude Code context")
    console.muted(f"  2. Load prompt: .laida/prompts/phase{phase}/{step_name}.yaml")
    console.muted("  3. Send prompt to Claude Code")
    console.muted("  4. Wait for completion")
    console.muted(f"  5. Verify outputs in: outputs/phase{phase}/{step_name}/")
