"""Cards CLI - Simplified with player names.

Design:
- Player names instead of positions
- Auto-registration on first deal
- No separate player_hash to manage
- Simple deck token in/out
"""

from __future__ import annotations

import sys
from typing import Any

import typer

from purefn.games.cards import engine

cards_app = typer.Typer(
    help="Cards engine: create decks, deal/discard/trade/exchange cards, and view state.",
    no_args_is_help=True,
)
view_app = typer.Typer(help="View game state")
cards_app.add_typer(view_app, name="view")


@cards_app.command()
def deck(
    seed: str | None = typer.Argument(
        None,
        metavar="SEED",
        help="Optional <SEED>; if omitted, PUREFN generates a random seed.",
    ),
    human: bool = typer.Option(False, "--human", help="Human-readable output"),
) -> None:
    """Create a new empty deck.

    Examples:
        purefn cards deck
        purefn cards deck poker-night
    """
    result = engine.create_deck(seed)
    _output_result(result, human)


@cards_app.command()
def deal(
    deck: str = typer.Argument(
        ...,
        metavar="DECK_TOKEN",
        help="Deck token <DECK_TOKEN> from 'purefn cards deck'.",
    ),
    player: str = typer.Argument(
        ...,
        metavar="PLAYER_NAME",
        help="Player name <PLAYER_NAME> (auto-registers if new).",
    ),
    num_cards: int = typer.Argument(
        ...,
        metavar="NUM_CARDS",
        help="Number <NUM_CARDS> of cards to deal.",
    ),
    human: bool = typer.Option(False, "--human", help="Human-readable output"),
) -> None:
    """Deal cards to a player.

    Auto-registers new players on first deal.

    Examples:
        purefn cards deal d3.ABC... alice 5
        purefn cards deal d3.ABC... bob 5
    """
    try:
        result = engine.deal(deck, player, num_cards)
        _output_result(result, human)
    except Exception as e:
        _output_error(str(e), human)


@cards_app.command()
def discard(
    deck: str = typer.Argument(
        ...,
        metavar="DECK_TOKEN",
        help="Deck token <DECK_TOKEN> from 'purefn cards deck'.",
    ),
    player: str = typer.Argument(
        ...,
        metavar="PLAYER_NAME",
        help="Player name <PLAYER_NAME>.",
    ),
    cards: list[str] = typer.Argument(
        ...,
        metavar="CARD",
        help="Cards <CARD> to discard (e.g., AS KH 7D).",
    ),
    human: bool = typer.Option(False, "--human", help="Human-readable output"),
) -> None:
    """Discard cards from a player's hand.

    Example:
        purefn cards discard d3.ABC... alice AS KH 7D
    """
    try:
        result = engine.discard(deck, player, list(cards))
        _output_result(result, human)
    except Exception as e:
        _output_error(str(e), human)


@cards_app.command()
def trade(
    deck: str = typer.Argument(
        ...,
        metavar="DECK_TOKEN",
        help="Deck token <DECK_TOKEN> from 'purefn cards deck'.",
    ),
    player1: str = typer.Argument(
        ...,
        metavar="PLAYER_ONE",
        help="First player <PLAYER_ONE>.",
    ),
    card1: str = typer.Argument(
        ...,
        metavar="CARD_ONE",
        help="Card <CARD_ONE> that PLAYER_ONE gives.",
    ),
    player2: str = typer.Argument(
        ...,
        metavar="PLAYER_TWO",
        help="Second player <PLAYER_TWO>.",
    ),
    card2: str = typer.Argument(
        ...,
        metavar="CARD_TWO",
        help="Card <CARD_TWO> that PLAYER_TWO gives.",
    ),
    human: bool = typer.Option(False, "--human", help="Human-readable output"),
) -> None:
    """Trade cards between two players.

    Example:
        purefn cards trade d3.ABC... alice AS bob KH
    """
    try:
        result = engine.trade(deck, player1, card1, player2, card2)
        _output_result(result, human)
    except Exception as e:
        _output_error(str(e), human)


@cards_app.command()
def exchange(
    deck: str = typer.Argument(
        ...,
        metavar="DECK_TOKEN",
        help="Deck token <DECK_TOKEN> from 'purefn cards deck'.",
    ),
    player: str = typer.Argument(
        ...,
        metavar="PLAYER_NAME",
        help="Player name <PLAYER_NAME>.",
    ),
    num_draw: int = typer.Argument(
        ...,
        metavar="NUM_DRAW",
        help="Number <NUM_DRAW> of cards to draw.",
    ),
    discard: list[str] = typer.Option(
        [],
        "--discard",
        "-d",
        metavar="CARD",
        help="Cards <CARD> to discard first.",
    ),
    human: bool = typer.Option(False, "--human", help="Human-readable output"),
) -> None:
    """Exchange cards (discard then draw).

    Examples:
        purefn cards exchange d3.ABC... alice 3 --discard AS KH
        purefn cards exchange d3.ABC... bob 2 -d AS -d KH
    """
    try:
        result = engine.exchange(deck, player, list(discard), num_draw)
        _output_result(result, human)
    except Exception as e:
        _output_error(str(e), human)


# View subcommands


@view_app.command("public")
def view_public(
    deck: str = typer.Argument(..., help="Deck token"),
    human: bool = typer.Option(False, "--human", help="Human-readable output"),
) -> None:
    """View public game state.

    Example:
        purefn cards view public d3.ABC...
    """
    try:
        info = engine.view_public(deck)
        if human:
            import json

            print(json.dumps(info, indent=2))
        else:
            import json

            print(json.dumps(info, separators=(",", ":")))
    except Exception as e:
        _output_error(str(e), human)


@view_app.command("hand")
def view_hand(
    deck: str = typer.Argument(..., help="Deck token"),
    player: str = typer.Argument(..., help="Player name"),
    human: bool = typer.Option(False, "--human", help="Human-readable output"),
) -> None:
    """View a player's hand.

    Example:
        purefn cards view hand d3.ABC... alice
    """
    try:
        hand = engine.hand_of(engine.decode_deck(deck), player)
        if human:
            import json

            print(json.dumps({"hand": hand}, indent=2))
        else:
            import json

            print(json.dumps({"hand": hand}, separators=(",", ":")))
    except Exception as e:
        _output_error(str(e), human)


@view_app.command("all")
def view_all_hands(
    deck: str = typer.Argument(..., help="Deck token"),
    human: bool = typer.Option(False, "--human", help="Human-readable output"),
) -> None:
    """View all players' hands (debug/spectator mode).

    Example:
        purefn cards view all d3.ABC...
    """
    try:
        hands = engine.view_all_hands(deck)
        if human:
            import json

            print(json.dumps(hands, indent=2))
        else:
            import json

            print(json.dumps(hands, separators=(",", ":")))
    except Exception as e:
        _output_error(str(e), human)


def _output_result(result: engine.DeckResult, human: bool) -> None:
    """Output result in appropriate format."""
    import json

    output: dict[str, Any] = {"deck": result.deck}
    if result.cards is not None:
        output["cards"] = result.cards
    if result.hand is not None:
        output["hand"] = result.hand

    if human:
        print(json.dumps(output, indent=2))
    else:
        print(json.dumps(output, separators=(",", ":")))


def _output_error(message: str, human: bool) -> None:
    """Output error message."""
    import json

    error_obj = {"error": message}
    if human:
        print(json.dumps(error_obj, indent=2), file=sys.stderr)
    else:
        print(json.dumps(error_obj, separators=(",", ":")), file=sys.stderr)
    sys.exit(1)
