from __future__ import annotations

from enum import Enum

from pydantic import BaseModel, Field


class AIProvider(str, Enum):
    OPENAI = "openai"
    ANTHROPIC = "anthropic"
    OPENROUTER = "openrouter"


class PlayerType(str, Enum):
    HUMAN = "human"
    AI = "ai"


class GameVariant(str, Enum):
    NO_LIMIT_HOLDEM = "no_limit_holdem"
    POT_LIMIT_OMAHA = "pot_limit_omaha"
    FIXED_LIMIT_HOLDEM = "fixed_limit_holdem"


class Street(str, Enum):
    PREFLOP = "preflop"
    FLOP = "flop"
    TURN = "turn"
    RIVER = "river"
    SHOWDOWN = "showdown"


class ActionType(str, Enum):
    FOLD = "fold"
    CHECK = "check"
    CALL = "call"
    BET = "bet"
    RAISE = "raise"
    ALL_IN = "all_in"


class PlayerStatus(str, Enum):
    ACTIVE = "active"
    FOLDED = "folded"
    ALL_IN = "all_in"
    SITTING_OUT = "sitting_out"


class Player(BaseModel):
    id: str
    name: str
    player_type: PlayerType
    provider: AIProvider | None = None
    model: str | None = None
    personality: str | None = None
    playing_style: str | None = None
    position: int
    stack: int
    status: PlayerStatus
    current_bet: int = 0
    hole_cards: list[str] | None = None
    is_dealer: bool = False
    is_small_blind: bool = False
    is_big_blind: bool = False
    last_action: ActionType | None = None


class PlayerConfig(BaseModel):
    id: str
    name: str
    player_type: PlayerType
    provider: AIProvider | None = None
    model: str | None = None
    personality: str | None = None
    playing_style: str | None = None
    starting_stack: int | None = None


class GameConfig(BaseModel):
    variant: GameVariant = GameVariant.NO_LIMIT_HOLDEM
    small_blind: int = Field(default=10, gt=0)
    big_blind: int = Field(default=20, gt=0)
    starting_stack: int = Field(default=10000, gt=0)
    max_players: int = Field(default=6, ge=2, le=9)
    ante: int = Field(default=0, ge=0)


class EngineOptions(BaseModel):
    enable_memory: bool = True
    enable_monte_carlo: bool = True
    debug: bool = False
    include_snapshot_in_events: bool = True


class PokerAction(BaseModel):
    action_type: ActionType
    amount: int | None = None


class AvailableAction(BaseModel):
    action_type: ActionType
    min_amount: int | None = None
    max_amount: int | None = None


class ActionHistoryEntry(BaseModel):
    player_name: str
    player_id: str
    action_type: ActionType
    amount: int | None = None
    street: Street
    pot_after: int


class OpponentView(BaseModel):
    name: str
    position: int
    stack: int
    current_bet: int
    status: PlayerStatus
    is_dealer: bool
    is_small_blind: bool
    is_big_blind: bool


class AIContext(BaseModel):
    hole_cards: list[str]
    board_cards: list[str]
    position: int
    stack: int
    pot: int
    current_bet: int
    call_amount: int
    min_raise: int | None = None
    max_raise: int | None = None
    opponents: list[OpponentView]
    action_history: list[ActionHistoryEntry]
    street: Street
    is_dealer: bool = False
    is_small_blind: bool = False
    is_big_blind: bool = False
    playing_style: str | None = None


class ShowdownResult(BaseModel):
    name: str
    amount: int
    hand: str


class TokenUsage(BaseModel):
    provider: AIProvider
    model: str
    input_tokens: int = 0
    output_tokens: int = 0
    total_tokens: int = 0
    cache_creation_input_tokens: int | None = None
    cache_read_input_tokens: int | None = None
    reasoning_tokens: int | None = None
    accepted_prediction_tokens: int | None = None
    rejected_prediction_tokens: int | None = None
    raw_usage: dict[str, object] = Field(default_factory=dict)
    provider_reported_cost: float | None = None


class AIDecisionDetails(BaseModel):
    player_id: str
    player_name: str
    provider: AIProvider
    model: str
    rationale: str
    tool_call: str | None = None
    arguments: dict[str, str | int | float | bool | None] | None = None
    token_usage: TokenUsage | None = None


class PlayerSnapshot(BaseModel):
    id: str
    name: str
    player_type: PlayerType
    provider: AIProvider | None = None
    model: str | None = None
    position: int
    stack: int
    status: PlayerStatus
    current_bet: int
    is_dealer: bool
    is_small_blind: bool
    is_big_blind: bool
    last_action: ActionType | None = None
    hole_cards: list[str] | None = None


class GameSnapshot(BaseModel):
    game_id: str
    game_name: str
    hand_number: int
    street: Street
    pot: int
    current_bet: int
    board_cards: list[str]
    players: list[PlayerSnapshot]
    current_actor_id: str | None = None
    current_actor_name: str | None = None
    hand_active: bool
    showdown_results: list[ShowdownResult] = Field(default_factory=list)


class SimulationResult(BaseModel):
    win: float
    tie: float
    lose: float
    iterations: int


class WinProbabilityResult(BaseModel):
    win_probability: float
    tie_probability: float
    lose_probability: float
    win_percentage: float
    iterations: int
    message: str


class PotOddsResult(BaseModel):
    pot_odds: float
    pot_odds_ratio: str
    pot_odds_percentage: float
    required_equity: float
    required_equity_percentage: float
    equity: float
    equity_percentage: float
    equity_difference: float
    expected_value: float


class EVResult(BaseModel):
    action: str
    ev: float
    cost: int = 0
    potential_win: int = 0
    message: str
