"""Colony CLI commands — start, stop, status, report."""

from __future__ import annotations

import asyncio
import os
import signal
from pathlib import Path

import typer
import yaml

from fliiq.cli import display

colony_app = typer.Typer(help="Manage Fliiq Colony experiments")


def _resolve_paths() -> tuple[Path, Path, Path]:
    """Resolve project root, fliiq dir, and colony dir."""
    from fliiq.runtime.config import resolve_fliiq_dir

    try:
        fliiq_dir = resolve_fliiq_dir(require_local=True)
    except FileNotFoundError:
        display.print_error("Colony requires a local .fliiq/ directory. Run `fliiq init --project` first.")
        raise typer.Exit(1) from None

    project_root = fliiq_dir.parent
    colony_dir = project_root / ".colony"
    return project_root, fliiq_dir, colony_dir


@colony_app.command("start")
def start(
    duration: float = typer.Option(24.0, "--duration", "-d", help="Experiment duration in hours"),
    dry_run: bool = typer.Option(False, "--dry-run", help="Short run (2h) with doubled cooldowns"),
    mission: str = typer.Option("", "--mission", "-m", help="Directed mode: mission objective for all agents"),
) -> None:
    """Start a Colony experiment."""
    from fliiq.runtime.agent.setup import resolve_llm_config
    from fliiq.runtime.colony.config import load_colony_config
    from fliiq.runtime.colony.orchestrator import Orchestrator

    project_root, _, colony_dir = _resolve_paths()

    # Auto mode (no --mission) is internal-only, gated behind FLIIQ_COLONY env var
    if not mission and not os.environ.get("FLIIQ_COLONY"):
        display.print_error(
            "Colony auto mode is not available.\n"
            "Use --mission to run Colony in directed mode:\n"
            '  fliiq colony start --mission "your objective here"'
        )
        raise typer.Exit(1)

    config = load_colony_config(colony_dir)

    # Apply mission if provided
    if mission:
        config.mission = mission
        display.console.print(f"[bold]Mission:[/bold] {mission}")

    if dry_run:
        if mission:
            # Directed dry run: 15 min
            config.experiment_duration_hours = 0.25
            config.code_freeze_at_hour = 0.20
        else:
            config.experiment_duration_hours = 2.0
            config.code_freeze_at_hour = 1.75
        config.cooldowns = {k: v * 2 for k, v in config.cooldowns.items()}
        dry_label = "15min" if mission else "2h"
        display.console.print(f"[dim]Dry run mode: {dry_label} duration, doubled cooldowns[/dim]")
    elif mission:
        # Directed mode: default 1h, hard cap at 1h
        effective = min(duration, 1.0) if duration != 24.0 else 1.0
        config.experiment_duration_hours = effective
        config.code_freeze_at_hour = effective - (10 / 60)  # 10 min before end
    else:
        config.experiment_duration_hours = duration

    try:
        llm_config = resolve_llm_config(
            model_override=config.llm_model or None,
        )
    except RuntimeError as e:
        display.print_error(str(e))
        raise typer.Exit(1) from None

    orchestrator = Orchestrator(project_root, colony_dir, llm_config, config)

    # Graceful shutdown on Ctrl+C
    loop = asyncio.new_event_loop()

    def _signal_handler(signum: int, frame: object) -> None:
        display.console.print("\n[dim]Stopping colony...[/dim]")
        loop.create_task(orchestrator.stop())

    signal.signal(signal.SIGINT, _signal_handler)
    signal.signal(signal.SIGTERM, _signal_handler)

    display.console.print(f"Starting Colony experiment ({config.experiment_duration_hours}h)")
    loop.run_until_complete(orchestrator.start())
    loop.close()


@colony_app.command("stop")
def stop() -> None:
    """Stop a running Colony experiment."""
    _, _, colony_dir = _resolve_paths()
    state_file = colony_dir / "state" / "colony_state.yaml"

    if not state_file.is_file():
        display.console.print("No colony experiment found.")
        return

    data = yaml.safe_load(state_file.read_text()) or {}
    if data.get("status") == "stopped":
        display.console.print("Colony already stopped.")
        return

    data["status"] = "stopped"
    state_file.write_text(yaml.dump(data, default_flow_style=False))
    display.console.print("Colony stop signal sent.")


@colony_app.command("status")
def status() -> None:
    """Show Colony experiment status."""
    _, _, colony_dir = _resolve_paths()
    state_file = colony_dir / "state" / "colony_state.yaml"

    if not state_file.is_file():
        display.console.print("No colony experiment data found.")
        return

    data = yaml.safe_load(state_file.read_text()) or {}
    display.console.print(f"Experiment:  {data.get('experiment_id', '?')}")
    display.console.print(f"Branch:      {data.get('branch_name', '?')}")
    display.console.print(f"Status:      {data.get('status', '?')}")
    mission_val = data.get("mission", "")
    if mission_val:
        display.console.print(f"Mission:     {mission_val}")
    display.console.print(f"Started:     {data.get('started_at', '?')}")
    display.console.print(f"Cycles:      {data.get('cycle_count', 0)}")

    # Proposal count
    proposals_dir = colony_dir / "state" / "proposals"
    if proposals_dir.is_dir():
        count = len(list(proposals_dir.glob("PROP-*.yaml")))
        display.console.print(f"Proposals:   {count}")

    # Intel brief count
    intel_dir = colony_dir / "state" / "intelligence"
    if intel_dir.is_dir():
        count = len(list(intel_dir.glob("INTEL-*.yaml")))
        display.console.print(f"Briefs:      {count}")

    # Recent timeline
    from fliiq.runtime.colony.state import StateManager

    state = StateManager(colony_dir)
    timeline = state.get_timeline(limit=5)
    if timeline:
        display.console.print("\nRecent activity:")
        for entry in timeline:
            time_str = entry.time.strftime("%H:%M") if hasattr(entry.time, "strftime") else str(entry.time)
            display.console.print(f"  [{time_str}] {entry.agent}: {entry.action[:80]}")


@colony_app.command("report")
def report(
    html: bool = typer.Option(
        False, "--html", help="Generate HTML report",
    ),
) -> None:
    """Generate or view the session report."""
    project_root, _, colony_dir = _resolve_paths()

    from fliiq.runtime.colony.reporting import ReportGenerator
    from fliiq.runtime.colony.state import StateManager

    state = StateManager(colony_dir)
    colony_state = state.load_colony_state()

    if not colony_state:
        display.console.print("No colony experiment data found.")
        return

    gen = ReportGenerator(state, project_root)

    if html:
        path = gen.generate_html_report(colony_state.experiment_id)
        display.console.print(f"HTML report: {path}")
    else:
        path = gen.generate_session_report(
            colony_state.experiment_id,
        )
        display.console.print(f"Report generated: {path}")
        display.console.print(path.read_text())
