"""
League catalog — archetypes, market taxonomy, and self-documenting discovery.

Every league has an **archetype** that determines its natural market menu.
A Racing sport has podiums and exactas. A Combat sport has fight winners.
This module encodes that structure so the SDK is self-documenting.

Data scientists get instant context::

    f1 = client.get_league("f1")
    f1.archetype     # → "racing"
    f1.markets       # → ["moneyline", "matchup", "over_under", "exacta", ...]
    f1.describe()    # pretty-prints the full market menu with method names

Internal use: the catalog is a static mapping. No API calls required.
"""

from enum import Enum
from typing import Dict, List, Optional, NamedTuple


# ── Archetypes ───────────────────────────────────────────────────────────────


class Archetype(str, Enum):
    """
    Sport archetype — determines the natural market structure.

    Each archetype produces different kinds of bettable outcomes.
    """
    RACING = "racing"
    HEAT_ELIMINATION = "heat_elimination"
    COMBAT = "combat"
    TEAM_BASED = "team_based"
    PRECISION = "precision"
    MULTI_DISCIPLINE = "multi_discipline"


ARCHETYPE_DESCRIPTIONS: Dict[Archetype, str] = {
    Archetype.RACING: "Timed competition with finishing positions (F1, Supercross, NHRA)",
    Archetype.HEAT_ELIMINATION: "Bracket/heat progression with event winners (WSL, SLS)",
    Archetype.COMBAT: "1v1 bout-based competition (BKFC, Power Slap)",
    Archetype.TEAM_BASED: "Team vs team match competition (MASL, NLL)",
    Archetype.PRECISION: "Individual skill/tournament competition (Disc Golf, Jai Alai)",
    Archetype.MULTI_DISCIPLINE: "Multiple sport disciplines in one event (X Games)",
}


# ── League → Archetype classification ────────────────────────────────────────


LEAGUE_ARCHETYPES: Dict[str, Archetype] = {
    # Racing
    "f1": Archetype.RACING,
    "spr": Archetype.RACING,
    "nrx": Archetype.RACING,
    "motocrs": Archetype.RACING,
    "motoamerica": Archetype.RACING,
    "nhra": Archetype.RACING,
    "usac": Archetype.RACING,
    "sprmtcrs": Archetype.RACING,
    "hlrs": Archetype.RACING,
    "worldoutlaws": Archetype.RACING,
    # Heat Elimination
    "wsl": Archetype.HEAT_ELIMINATION,
    "sls": Archetype.HEAT_ELIMINATION,
    "fdrift": Archetype.HEAT_ELIMINATION,
    # Combat
    "bkfc": Archetype.COMBAT,
    "byb": Archetype.COMBAT,
    "powerslap": Archetype.COMBAT,
    "lux": Archetype.COMBAT,
    "raf": Archetype.COMBAT,
    # Team-Based
    "masl": Archetype.TEAM_BASED,
    "nll": Archetype.TEAM_BASED,
    "athletesunlimited": Archetype.TEAM_BASED,
    "gsoc": Archetype.TEAM_BASED,
    # Precision
    "dgpt": Archetype.PRECISION,
    "jaialai": Archetype.PRECISION,
    # Multi-Discipline
    "xgame": Archetype.MULTI_DISCIPLINE,
}


# ── Market taxonomy ──────────────────────────────────────────────────────────

class MarketInfo(NamedTuple):
    """Metadata for a single market type."""
    api_name: str          # API field name (e.g. "eventWinnerProjections")
    native_name: str       # Sportsbook-friendly name (e.g. "moneyline")
    method: str            # SDK method name (e.g. "get_moneylines")
    description: str       # Human-readable description
    category: str          # "core", "position", "exotic", "prop"


# Map: API market name (without "Projections" suffix) → MarketInfo
MARKET_CATALOG: Dict[str, MarketInfo] = {
    "eventWinner": MarketInfo(
        api_name="eventWinner",
        native_name="moneyline",
        method="get_moneylines(event_id)",
        description="Who wins the event/race",
        category="core",
    ),
    "headToHead": MarketInfo(
        api_name="headToHead",
        native_name="matchup",
        method="get_matchups(event_id)",
        description="Head-to-head between two competitors",
        category="core",
    ),
    "heatWinner": MarketInfo(
        api_name="heatWinner",
        native_name="heat_winner",
        method="get_heat_winners(event_id)",
        description="Who wins individual heat/bout/fight",
        category="core",
    ),
    "podiums": MarketInfo(
        api_name="podiums",
        native_name="podium",
        method="get_podiums(event_id)",
        description="Top 3 finish",
        category="position",
    ),
    "shows": MarketInfo(
        api_name="shows",
        native_name="show",
        method="get_shows(event_id)",
        description="Top N finish (place/show)",
        category="position",
    ),
    "raceTop3": MarketInfo(
        api_name="raceTop3",
        native_name="top_3",
        method="get_top_finish_probabilities(event_id, top_n=3)",
        description="Top 3 finish probabilities",
        category="position",
    ),
    "raceTop5": MarketInfo(
        api_name="raceTop5",
        native_name="top_5",
        method="get_top_finish_probabilities(event_id, top_n=5)",
        description="Top 5 finish probabilities",
        category="position",
    ),
    "raceTop10": MarketInfo(
        api_name="raceTop10",
        native_name="top_10",
        method="get_top_finish_probabilities(event_id, top_n=10)",
        description="Top 10 finish probabilities",
        category="position",
    ),
    "overUnder": MarketInfo(
        api_name="overUnder",
        native_name="over_under",
        method="get_totals(event_id)",
        description="Position/points over/under totals",
        category="prop",
    ),
    "multiOverUnder": MarketInfo(
        api_name="multiOverUnder",
        native_name="multi_over_under",
        method="get_totals(event_id)",
        description="Combined totals across categories",
        category="prop",
    ),
    "propBets": MarketInfo(
        api_name="propBets",
        native_name="props",
        method="get_player_props(event_id)",
        description="Player proposition bets",
        category="prop",
    ),
    "fastestLap": MarketInfo(
        api_name="fastestLap",
        native_name="fastest_lap",
        method="get_fastest_lap(event_id)",
        description="Fastest lap/time",
        category="exotic",
    ),
    "eventExacta": MarketInfo(
        api_name="eventExacta",
        native_name="exacta",
        method="get_exactas(event_id)",
        description="Exact 1-2 finish order",
        category="exotic",
    ),
    "heatExacta": MarketInfo(
        api_name="heatExacta",
        native_name="heat_exacta",
        method="get_exactas(event_id)",
        description="Exact 1-2 finish in a heat",
        category="exotic",
    ),
    "trifectasEvent": MarketInfo(
        api_name="trifectasEvent",
        native_name="trifecta",
        method="get_odds(event_id, 'trifecta')",
        description="Exact 1-2-3 finish order",
        category="exotic",
    ),
    "secondPlace": MarketInfo(
        api_name="secondPlace",
        native_name="second_place",
        method="get_odds(event_id, 'second_place')",
        description="Second place finisher",
        category="position",
    ),
    "holeShot": MarketInfo(
        api_name="holeShot",
        native_name="hole_shot",
        method="get_odds(event_id, 'hole_shot')",
        description="First to the first turn (motocross)",
        category="exotic",
    ),
    "dreamTeam": MarketInfo(
        api_name="dreamTeam",
        native_name="dream_team",
        method="get_dream_team(event_id)",
        description="Fantasy team combination",
        category="exotic",
    ),
}


# Reverse lookup: native name → API name (used by _resolve_market in client.py)
NATIVE_TO_API: Dict[str, str] = {
    info.native_name: info.api_name for info in MARKET_CATALOG.values()
}


# ── League metadata ──────────────────────────────────────────────────────────


# Full names for leagues (supplements API data when name is missing)
LEAGUE_NAMES: Dict[str, str] = {
    "wsl": "World Surf League",
    "sls": "Street League Skateboarding",
    "nrx": "Nitrocross",
    "spr": "Supercross",
    "masl": "Major Arena Soccer League",
    "bkfc": "Bare Knuckle Fighting Championship",
    "f1": "Formula 1",
    "motocrs": "Pro Motocross",
    "fdrift": "Formula Drift",
    "jaialai": "World Jai Alai",
    "gsoc": "Goal Soccer",
    "motoamerica": "MotoAmerica",
    "byb": "BYB Extreme Fighting",
    "powerslap": "Power Slap",
    "usac": "USAC Racing",
    "nhra": "National Hot Rod Association",
    "sprmtcrs": "SuperMotocross",
    "hlrs": "High Limit Racing",
    "xgame": "X Games",
    "worldoutlaws": "World of Outlaws",
    "dgpt": "Disc Golf Pro Tour",
    "athletesunlimited": "Athletes Unlimited",
    "lux": "LUX Fight League",
    "raf": "Real American Freestyle",
    "nll": "National Lacrosse League",
    "mltt": "Major League Table Tennis",
    "spectation": "Spectation Sports",
}


# ── Helpers ──────────────────────────────────────────────────────────────────


def get_archetype(league: str) -> Optional[Archetype]:
    """Get the archetype for a league key. Returns None if unknown."""
    return LEAGUE_ARCHETYPES.get(league.lower())


def get_league_name(league: str) -> str:
    """Get the full name for a league key. Returns the key if unknown."""
    return LEAGUE_NAMES.get(league.lower(), league.upper())


def get_market_info(api_name: str) -> Optional[MarketInfo]:
    """Get MarketInfo for an API market name (with or without 'Projections' suffix)."""
    clean = api_name.replace("Projections", "")
    # Direct lookup
    info = MARKET_CATALOG.get(clean)
    if info:
        return info
    # Handle API quirks: "heat" → "heatWinner", "propBet" → "propBets"
    aliases = {
        "heat": "heatWinner",
        "propBet": "propBets",
        "podium": "podiums",
        "trifectas": "trifectasEvent",
        "trifectasEvent": "trifectasEvent",
        "exactas": "eventExacta",
        "exactasEvent": "eventExacta",
        "exactasHeat": "heatExacta",
        "fastestLapProjections": "fastestLap",
    }
    return MARKET_CATALOG.get(aliases.get(clean, ""))


def get_league_markets(supported_markets: List[str]) -> List[MarketInfo]:
    """
    Convert a league's supportedMarkets list to rich MarketInfo objects.

    Args:
        supported_markets: Raw list from API (e.g. ["eventWinnerProjections", "headToHeadProjections"])

    Returns:
        List of MarketInfo, sorted by category priority (core → position → prop → exotic)
    """
    category_order = {"core": 0, "position": 1, "prop": 2, "exotic": 3}
    infos = []
    for m in supported_markets:
        info = get_market_info(m)
        if info:
            infos.append(info)
    infos.sort(key=lambda x: (category_order.get(x.category, 9), x.native_name))
    return infos


def format_league_description(
    league_key: str,
    league_name: Optional[str] = None,
    supported_markets: Optional[List[str]] = None,
) -> str:
    """
    Format a rich description of a league's market menu.

    Returns a clean ASCII card that works in notebooks, terminals, and REPLs.
    """
    name = league_name or get_league_name(league_key)
    archetype = get_archetype(league_key)
    arch_str = archetype.value.replace("_", " ").title() if archetype else "Unknown"
    arch_desc = ARCHETYPE_DESCRIPTIONS.get(archetype, "") if archetype else ""

    markets = get_league_markets(supported_markets or [])

    lines = []
    # Header
    width = 72
    lines.append("┌" + "─" * width + "┐")
    lines.append("│" + f"  {name}  ({league_key})".ljust(width) + "│")
    lines.append("│" + f"  Archetype: {arch_str}".ljust(width) + "│")
    if arch_desc:
        lines.append("│" + f"  {arch_desc}".ljust(width) + "│")
    lines.append("│" + " " * width + "│")

    if markets:
        lines.append("│" + "  Available Markets:".ljust(width) + "│")
        lines.append("│" + "  " + "─" * (width - 4) + "  │")

        # Group by category
        current_cat = None
        for m in markets:
            if m.category != current_cat:
                current_cat = m.category
                if current_cat != "core":
                    lines.append("│" + " " * width + "│")

            method_col = f"  .{m.method}"
            desc_col = m.description
            # Pad method to 46 chars, then description
            if len(method_col) > 44:
                method_col = method_col[:42] + ".."
            row = f"{method_col:<46}{desc_col}"
            if len(row) > width:
                row = row[:width - 1] + "…"
            lines.append("│" + row.ljust(width) + "│")

        lines.append("│" + " " * width + "│")
        lines.append("│" + f"  {len(markets)} market types available".ljust(width) + "│")
    else:
        lines.append("│" + "  No markets configured yet".ljust(width) + "│")

    lines.append("│" + " " * width + "│")
    lines.append("│" + "  Quick Start:".ljust(width) + "│")
    lines.append("│" + f"    league = client.get_league(\"{league_key}\")".ljust(width) + "│")
    if markets:
        # Pick the first "core" market for the example
        core = [m for m in markets if m.category == "core"]
        first = core[0] if core else markets[0]
        lines.append("│" + f"    odds = league.{first.method}".ljust(width) + "│")
    lines.append("│" + "    print(odds)        # clean table".ljust(width) + "│")
    lines.append("│" + "    odds.df            # → pandas DataFrame".ljust(width) + "│")
    lines.append("└" + "─" * width + "┘")

    return "\n".join(lines)


def format_catalog_table(
    leagues: list,
) -> str:
    """
    Format a catalog overview table showing all leagues with archetypes.

    Args:
        leagues: List of SportsListing objects or dicts with key, name, supportedMarkets
    """
    lines = []
    lines.append("AltSportsData League Catalog")
    lines.append("")

    header = f"{'League':<14} {'Name':<32} {'Archetype':<20} {'Markets':<6} {'Market Types'}"
    lines.append(header)
    lines.append("─" * len(header))

    for lg in leagues:
        if hasattr(lg, "league_key"):
            key = lg.league_key
            name = lg.name or get_league_name(key)
            raw_markets = lg.supportedMarkets or []
        elif isinstance(lg, dict):
            key = lg.get("key", lg.get("league_key", ""))
            name = lg.get("name", get_league_name(key))
            raw_markets = lg.get("supportedMarkets", [])
        else:
            continue

        archetype = get_archetype(key)
        arch_str = archetype.value.replace("_", " ").title() if archetype else "—"
        market_infos = get_league_markets(raw_markets)
        market_names = ", ".join(m.native_name for m in market_infos[:5])
        if len(market_infos) > 5:
            market_names += f" +{len(market_infos) - 5}"

        name_display = name if name and len(name) <= 30 else (name[:28] + ".." if name else key)

        lines.append(
            f"{key:<14} {name_display:<32} {arch_str:<20} {len(market_infos):<6} {market_names}"
        )

    lines.append("")
    lines.append(f"  {len(leagues)} leagues")

    return "\n".join(lines)
