"""CLI commands for the chess game."""

from __future__ import annotations

import json
import sys

import typer

from purefn.games.chess import engine

app = typer.Typer(help="Chess board operations (stateless, no validation)")


def _format_result(result: engine.BoardResult, human: bool = False) -> str:
    """Format a board result for output."""
    if human:
        return result.ascii
    return json.dumps(
        {
            "board": result.board,
            "fen": result.fen,
        }
    )


@app.command()
def new(
    variant: str = typer.Option("standard", help="Board variant: standard or empty"),
    human: bool = typer.Option(False, "--human", help="Human-readable output"),
) -> None:
    """Create a new chess board.

    Examples:
        purefn chess new
        purefn chess new --variant empty
        purefn chess new --human
    """
    try:
        result = engine.new_board(variant)
        output = _format_result(result, human)
        typer.echo(output)
    except Exception as e:
        typer.echo(f"Error: {e}", err=True)
        sys.exit(1)


@app.command()
def place(
    board: str = typer.Argument(..., help="Board token"),
    square: str = typer.Argument(..., help="Square (e.g., e4)"),
    piece: str = typer.Argument(..., help="Piece (e.g., wP, bK)"),
    human: bool = typer.Option(False, "--human", help="Human-readable output"),
) -> None:
    """Place a piece on the board.

    Piece format: <color><type>
    - Colors: w (white), b (black)
    - Types: P (pawn), N (knight), B (bishop), R (rook), Q (queen), K (king)

    Examples:
        purefn chess place BOARD e4 wP
        purefn chess place BOARD e7 bK --human
    """
    try:
        result = engine.place_piece(board, square, piece)
        output = _format_result(result, human)
        typer.echo(output)
    except Exception as e:
        typer.echo(f"Error: {e}", err=True)
        sys.exit(1)


@app.command()
def remove(
    board: str = typer.Argument(..., help="Board token"),
    square: str = typer.Argument(..., help="Square (e.g., e4)"),
    human: bool = typer.Option(False, "--human", help="Human-readable output"),
) -> None:
    """Remove a piece from the board.

    Examples:
        purefn chess remove BOARD e4
        purefn chess remove BOARD e7 --human
    """
    try:
        result = engine.remove_piece(board, square)
        output = _format_result(result, human)
        typer.echo(output)
    except Exception as e:
        typer.echo(f"Error: {e}", err=True)
        sys.exit(1)


@app.command()
def move(
    board: str = typer.Argument(..., help="Board token"),
    from_square: str = typer.Argument(..., help="From square (e.g., e2)"),
    to_square: str = typer.Argument(..., help="To square (e.g., e4)"),
    human: bool = typer.Option(False, "--human", help="Human-readable output"),
) -> None:
    """Move a piece on the board (no validation).

    Examples:
        purefn chess move BOARD e2 e4
        purefn chess move BOARD e7 e5 --human
    """
    try:
        result = engine.move_piece(board, from_square, to_square)
        output = _format_result(result, human)
        typer.echo(output)
    except Exception as e:
        typer.echo(f"Error: {e}", err=True)
        sys.exit(1)


@app.command()
def clear(
    board: str = typer.Argument(..., help="Board token"),
    human: bool = typer.Option(False, "--human", help="Human-readable output"),
) -> None:
    """Clear all pieces from the board.

    Examples:
        purefn chess clear BOARD
        purefn chess clear BOARD --human
    """
    try:
        result = engine.clear_board(board)
        output = _format_result(result, human)
        typer.echo(output)
    except Exception as e:
        typer.echo(f"Error: {e}", err=True)
        sys.exit(1)


@app.command(name="import")
def import_fen_cmd(
    fen: str = typer.Argument(..., help="FEN string"),
    human: bool = typer.Option(False, "--human", help="Human-readable output"),
) -> None:
    """Import a board from FEN notation.

    Examples:
        purefn chess import "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
        purefn chess import "8/8/8/4k3/8/8/4K3/8 w - - 0 1" --human
    """
    try:
        result = engine.import_fen(fen)
        output = _format_result(result, human)
        typer.echo(output)
    except Exception as e:
        typer.echo(f"Error: {e}", err=True)
        sys.exit(1)


@app.command(name="export")
def export_fen_cmd(
    board: str = typer.Argument(..., help="Board token"),
) -> None:
    """Export a board to FEN notation.

    Examples:
        purefn chess export BOARD
    """
    try:
        fen = engine.export_fen(board)
        typer.echo(fen)
    except Exception as e:
        typer.echo(f"Error: {e}", err=True)
        sys.exit(1)


@app.command()
def view(
    board: str = typer.Argument(..., help="Board token"),
    human: bool = typer.Option(False, "--human", help="Human-readable output"),
) -> None:
    """View the current board state.

    Examples:
        purefn chess view BOARD
        purefn chess view BOARD --human
    """
    try:
        info = engine.view_board(board)
        if human:
            typer.echo(info["ascii"])
            typer.echo(f"\nFEN: {info['fen']}")
            typer.echo(f"Turn: {info['turn']}")
            typer.echo(f"Pieces: {len(info['pieces'])}")
        else:
            typer.echo(json.dumps(info, indent=2))
    except Exception as e:
        typer.echo(f"Error: {e}", err=True)
        sys.exit(1)


@app.command()
def load(
    source: str = typer.Argument(
        ..., help="Source: FEN, PGN, URL, Lichess ID, file path, or '-' for stdin"
    ),
    human: bool = typer.Option(False, "--human", help="Human-readable output"),
) -> None:
    """Load a chess position from any source (auto-detects format).

    Supported sources:
    - FEN string: "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
    - PGN string: "1. e4 e5 2. Nf3..."
    - URL: https://lichess.org/q7ZvsdUF
    - Lichess game ID: q7ZvsdUF
    - File path: positions/endgame.fen
    - stdin: - (use echo or pipe)

    Examples:
        purefn chess load "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
        purefn chess load q7ZvsdUF
        purefn chess load https://lichess.org/q7ZvsdUF
        purefn chess load positions/game.pgn
        echo "rnbq..." | purefn chess load -
    """
    try:
        from purefn.games.chess import loader

        fen = loader.load_from_source(source)
        result = engine.import_fen(fen)
        output = _format_result(result, human)
        typer.echo(output)
    except Exception as e:
        typer.echo(f"Error: {e}", err=True)
        sys.exit(1)


@app.command()
def save(
    board: str = typer.Argument(..., help="Board token (or '-' for stdin)"),
    output: str = typer.Option(None, "--output", "-o", help="Output file (default: stdout)"),
    format: str = typer.Option(
        "fen", "--format", "-f", help="Output format: fen, pgn (default: fen)"
    ),
) -> None:
    """Save a chess board to FEN or PGN format.

    Examples:
        purefn chess save BOARD
        purefn chess save BOARD --output game.fen
        purefn chess save BOARD --format pgn
        echo BOARD | purefn chess save -
    """
    try:
        # Handle stdin
        if board == "-":
            board = sys.stdin.read().strip()
            # If stdin contains JSON, extract the board token
            if board.startswith("{"):
                data = json.loads(board)
                board = data.get("board", data.get("global", ""))

        # Export FEN
        fen = engine.export_fen(board)

        # Format output
        if format.lower() == "pgn":
            # Create minimal PGN with FEN setup
            output_text = f'[FEN "{fen}"]\n[SetUp "1"]\n\n'
        else:
            output_text = fen

        # Write output
        if output:
            with open(output, "w") as f:
                f.write(output_text)
            typer.echo(f"Saved to {output}", err=True)
        else:
            typer.echo(output_text)

    except Exception as e:
        typer.echo(f"Error: {e}", err=True)
        sys.exit(1)


@app.command()
def puzzle(
    human: bool = typer.Option(False, "--human", help="Human-readable output"),
) -> None:
    """Load today's Lichess puzzle.

    Returns the puzzle position and metadata.

    Examples:
        purefn chess puzzle
        purefn chess puzzle --human
    """
    try:
        from purefn.games.chess import loader

        fen, metadata = loader.load_lichess_puzzle()
        result = engine.import_fen(fen)

        if human:
            typer.echo(result.ascii)
            typer.echo(f"\nFEN: {fen}")
            typer.echo(f"Rating: {metadata.get('rating', 'N/A')}")
            typer.echo(f"Themes: {', '.join(metadata.get('themes', []))}")
            typer.echo(f"Plays: {metadata.get('plays', 'N/A')}")
        else:
            output = {
                "board": result.board,
                "fen": fen,
                "puzzle": metadata,
            }
            typer.echo(json.dumps(output, indent=2))

    except Exception as e:
        typer.echo(f"Error: {e}", err=True)
        sys.exit(1)
