import os
from pathlib import Path

import click
from rich.console import Console

from cambc.config import find_config

console = Console()


def resolve_bot_path(path_str: str, bots_dir: Path) -> str:
    """Resolve a bot path. Checks raw path first, then bots_dir/path."""
    p = Path(path_str)

    # If it's already a valid path, use it directly
    if not p.exists() and not p.is_absolute():
        # Try resolving relative to bots_dir
        candidate = bots_dir / path_str
        if candidate.exists():
            p = candidate

    if p.is_dir():
        main_py = p / "main.py"
        if main_py.is_file():
            return str(main_py.resolve())
        raise click.BadParameter(
            f"Directory '{path_str}' does not contain main.py"
        )
    if p.is_file():
        return str(p.resolve())
    raise click.BadParameter(f"Bot not found: '{path_str}'")


@click.command()
@click.argument("bot_a")
@click.argument("bot_b")
@click.argument("map_path", required=False, default=None)
@click.option("--replay", default=None, help="Output replay path")
@click.option("--seed", default=None, type=int)
@click.option("--watch", "auto_watch", is_flag=True, help="Open visualizer after match")
def run(bot_a: str, bot_b: str, map_path: str | None, replay: str | None, seed: int | None, auto_watch: bool):
    """Run a local match between two bots.

    MAP_PATH is optional — if omitted, uses the first .map26 file in the maps directory.
    """
    from cambc.cambc_engine import run_game

    config, project_root = find_config()

    # Apply config defaults where CLI didn't override
    replay = replay or config.replay
    seed = seed if seed is not None else config.seed
    bots_dir = (project_root / config.bots_dir).resolve()
    maps_dir = (project_root / config.maps_dir).resolve()

    # Game types are re-exported in cambc/__init__.py via _types.py,
    # so `from cambc import *` already works. engine_root is passed to the
    # Rust engine for sys.path setup (redundant here, needed by server binary).
    engine_root = str(Path(__file__).resolve().parent.parent)

    player_a = resolve_bot_path(bot_a, bots_dir)
    player_b = resolve_bot_path(bot_b, bots_dir)

    # Resolve map — pick first available if not specified
    if map_path is None:
        maps = sorted(maps_dir.glob("*.map26"))
        if not maps:
            console.print("[red]No .map26 files found in maps/ directory. Provide a map path.[/red]")
            raise SystemExit(1)
        mp = maps[0]
    else:
        mp = Path(map_path)
        if not mp.exists() and not mp.is_absolute():
            candidate = maps_dir / map_path
            if candidate.exists():
                mp = candidate
    resolved_map = str(mp.resolve())

    console.print(f"[bold]Running match:[/bold] {Path(player_a).name} vs {Path(player_b).name}")
    console.print(f"  Map: {mp.name}  Seed: {seed}  Replay: {replay}")

    try:
        run_game(player_a, player_b, engine_root, resolved_map, replay, seed)
    except Exception as e:
        console.print(f"[red bold]Error:[/red bold] {e}")
        raise SystemExit(1)

    if os.path.exists(replay):
        console.print(f"[green]Replay written to {replay}[/green]")

    if auto_watch:
        from cambc.commands import watch as watch_mod
        ctx = click.get_current_context()
        ctx.invoke(watch_mod.watch, replay_file=replay)
