"""
Abstract base class for bookmaker placement drivers.

Each driver must implement:
  login()        — authenticate and return True on success
  get_balance()  — return NGN balance or None
  place_bet()    — place a single bet, return BetResult
  verify_odds()  — return current odds for an outcome or None
"""
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Optional


def parse_numeric_event_id(event_id: str) -> str:
    """
    Extract the numeric ID from a scraper event_id string.

    Scraper formats:
      '1x_711938933_1X2'        → '711938933'
      'b9j_749016274_1X2'       → '749016274'
      'bk_34178592_110'         → '34178592'
      'bk_live_34178592_110'    → '34178592'
      'ab_12345'                → '12345'
      'ab_live_12345'           → '12345'

    For BCGame ('bcg_...') use the full event_id — handled by that driver directly.
    """
    for part in event_id.split('_'):
        if part.isdigit():
            return part
    return event_id   # fallback: return as-is


@dataclass
class BetResult:
    success:      bool
    bet_id:       Optional[str]   # bookmaker's bet/coupon reference
    odds_placed:  Optional[float] # actual odds the bet was accepted at
    stake_placed: Optional[float] # actual stake accepted (may differ if restricted)
    message:      str             # human-readable status or error


class PlacementDriver(ABC):

    @abstractmethod
    def login(self) -> bool:
        """Authenticate with the bookmaker. Returns True on success."""

    @abstractmethod
    def get_balance(self) -> Optional[float]:
        """Return current account balance in NGN, or None on failure."""

    @abstractmethod
    def place_bet(
        self,
        event_id:     str,
        outcome_name: str,
        odds:         float,
        stake:        float,
        market:       str  = '',    # e.g. '1X2', 'Over/Under 2.5', 'Asian Handicap -0.5'
        is_live:      bool = False,
        sport:        str  = 'football',
    ) -> BetResult:
        """
        Place a single bet leg.

        event_id:     bookmaker-internal numeric event ID
        outcome_name: e.g. 'Home', 'Away', 'Draw', 'Over', 'Under'
        odds:         expected decimal odds
        stake:        amount in NGN
        market:       market name — used to determine outcome type codes
        is_live:      True for in-play bets

        Returns a BetResult indicating success or failure.
        """

    @abstractmethod
    def verify_odds(self, event_id: str, outcome_name: str, market: str = '', is_live: bool = False, sport: str = 'football') -> Optional[float]:
        """
        Return the current live odds for a specific outcome, or None if unavailable.
        Used to confirm odds haven't moved before placing.
        """
