"""
BC.Game sportsbook scraper.

Endpoints discovered via Playwright network interception on bc.game

Prematch index:
  GET https://api-k-c7818b61-623.sptpub.com/api/v4/prematch/brand/{BRAND}/en/0
  → {top_events_versions: [...], rest_events_versions: [...]}

Data chunks (one per version):
  GET https://api-k-c7818b61-623.sptpub.com/api/v4/prematch/brand/{BRAND}/en/{version}
  → {events: {event_id: {...}}}

All chunks are merged; filtering is done locally.

Event structure:
  desc.sport        → sport ID string ("1"=Soccer, "2"=Basketball, "5"=Tennis)
  desc.competitors  → [{name: "..."}, {name: "..."}]  (index 0=home, 1=away)
  desc.scheduled    → Unix timestamp (seconds)
  state.status      → 0 = prematch, 1 = live
  markets           → {market_id: {specifier: {outcome_id: {"k": decimal_odds}}}}

Market / outcome ID mapping:
  market "1"   → 1X2       outcomes: "1"=Home "2"=Draw "3"=Away
  market "18"  → Total Goals (filter specifier "total=2.5")  "12"=Over "13"=Under
  market "219" → Basketball moneyline  "4"=Home "5"=Away
  market "186" → Tennis winner         "4"=Home "5"=Away
"""
import logging
from datetime import datetime, timezone
from typing import List, Dict

from scrapers.base import BaseScraper
from core.models import Event, Outcome

logger = logging.getLogger(__name__)

BRAND   = '2103509236163162112'
BASE    = 'https://api-k-c7818b61-623.sptpub.com/api'
IDX_URL = f'{BASE}/v4/prematch/brand/{BRAND}/en/0'
CHK_URL = f'{BASE}/v4/prematch/brand/{{brand}}/en/{{ver}}'

SPORT_IDS = {
    'football':   '1',
    'basketball': '2',
    'tennis':     '5',
}

# (market_id, specifier_filter_or_None) → {outcome_id: label}
MARKET_CONFIG = {
    'football': [
        ('1',  None,        {'1': 'Home', '2': 'Draw', '3': 'Away'}, '1X2'),
        ('18', 'total=2.5', {'12': 'Over', '13': 'Under'},           'Over/Under 2.5'),
    ],
    'basketball': [
        ('219', None, {'4': 'Home', '5': 'Away'}, 'Home/Away'),
    ],
    'tennis': [
        ('186', None, {'4': 'Home', '5': 'Away'}, 'Home/Away'),
    ],
}


class BCGameScraper(BaseScraper):

    def __init__(self):
        super().__init__('BCGame')
        self.session.headers.update({
            'Origin':  'https://bc.game',
            'Referer': 'https://bc.game/',
        })
        self._cached_events: Dict = {}

    # ── Public API ────────────────────────────────────────────────────────────

    def get_all_events(self) -> List[Event]:
        """Override to fetch all chunks once, then parse all sports."""
        raw_events, tournaments = self._fetch_all_events()
        result: List[Event] = []
        for sport in ['football', 'basketball', 'tennis']:
            try:
                events = self._parse_sport(raw_events, tournaments, sport)
                result.extend(events)
                logger.info(f'[BCGame] {sport}: {len(events)} events')
            except Exception as ex:
                logger.error(f'[BCGame] {sport} parse error: {ex}')
        return result

    def get_events(self, sport: str) -> List[Event]:
        """Used when called individually; re-uses cached raw events if available."""
        raw_events, tournaments = self._fetch_all_events()
        return self._parse_sport(raw_events, tournaments, sport)

    # ── Fetch ─────────────────────────────────────────────────────────────────

    def _fetch_all_events(self) -> tuple:
        """Fetch all prematch snapshot chunks. Returns (events_dict, tournaments_dict)."""
        idx = self.session.get(IDX_URL, timeout=15)
        idx.raise_for_status()
        idx_data = idx.json()

        versions = (
            idx_data.get('top_events_versions', [])
            + idx_data.get('rest_events_versions', [])
        )

        merged_events: Dict = {}
        merged_tournaments: Dict = {}
        for ver in versions:
            url = CHK_URL.format(brand=BRAND, ver=ver)
            try:
                r = self.session.get(url, timeout=20)
                r.raise_for_status()
                chunk = r.json()
                for eid, ev in chunk.get('events', {}).items():
                    if ev is not None:
                        merged_events[eid] = ev
                merged_tournaments.update(chunk.get('tournaments', {}))
            except Exception as ex:
                logger.warning(f'[BCGame] chunk {ver} failed: {ex}')

        logger.debug(f'[BCGame] fetched {len(merged_events)} events across {len(versions)} chunks')
        return merged_events, merged_tournaments

    # ── Parse ─────────────────────────────────────────────────────────────────

    def _parse_sport(self, raw_events: Dict, tournaments: Dict, sport: str) -> List[Event]:
        sport_id = SPORT_IDS.get(sport)
        if not sport_id:
            return []

        mkt_configs = MARKET_CONFIG.get(sport, [])
        result: List[Event] = []

        for eid, ev in raw_events.items():
            desc = ev.get('desc', {})

            if desc.get('sport') != sport_id:
                continue
            if desc.get('virtual', False):
                continue

            # Skip events whose scheduled time is in the past (already live/finished)
            ts = desc.get('scheduled')
            now_utc = datetime.now(timezone.utc).timestamp()
            if ts and ts < now_utc:
                continue

            comps = desc.get('competitors', [])
            if len(comps) < 2:
                continue
            home = comps[0].get('name', '').strip()
            away = comps[1].get('name', '').strip()
            if not home or not away:
                continue

            t_id = desc.get('tournament', '')
            league = tournaments.get(str(t_id), {}).get('name', '') if t_id else ''

            try:
                starts_at = datetime.utcfromtimestamp(ts) if ts else None
            except Exception:
                starts_at = None

            ev_markets = ev.get('markets', {})

            for mkt_id, spec_filter, outcome_map, market_label in mkt_configs:
                parsed = self._parse_market(ev_markets, mkt_id, spec_filter, outcome_map)
                if parsed:
                    result.append(Event(
                        event_id  = f'bcg_{eid}_{mkt_id}',
                        bookmaker = 'BCGame',
                        sport     = sport,
                        home_team = home,
                        away_team = away,
                        market    = market_label,
                        outcomes  = parsed,
                        starts_at = starts_at,
                        league    = league,
                    ))

        return result

    def _parse_market(
        self,
        ev_markets: Dict,
        mkt_id: str,
        spec_filter,
        outcome_map: Dict,
    ):
        mkt = ev_markets.get(mkt_id)
        if not mkt:
            return None

        # Pick the right specifier bucket
        if spec_filter is not None:
            spec_data = mkt.get(spec_filter)
        else:
            spec_data = mkt.get('')   # empty-string specifier = no specifier

        if not spec_data:
            return None

        outcomes = []
        for oid, label in outcome_map.items():
            entry = spec_data.get(oid)
            if not entry:
                continue
            try:
                odds = float(entry['k'])
            except (KeyError, TypeError, ValueError):
                continue
            if odds <= 1.0:
                continue
            outcomes.append(Outcome(name=label, odds=odds, bookmaker='BCGame'))

        if len(outcomes) == len(outcome_map):
            return outcomes
        return None
