"""
Stake calculation utilities for arbitrage betting.

For N outcome legs with decimal odds [o1, o2, ...] and total stake S:

  Stake on leg i  = S × (1/oi) / Σ(1/oj)
  Guaranteed return  = S / Σ(1/oj)
  Guaranteed profit  = return − S

Two entry points:
  calc_from_total(legs, total_stake)    — split a given total across legs
  calc_from_profit(legs, target_profit) — back-calculate stake for desired profit
"""
from dataclasses import dataclass
from typing import List


@dataclass
class LegStake:
    bookmaker:     str
    outcome:       str
    odds:          float
    odds_key:      str          # bookmaker-internal odds key (e.g. 'S_1X2_1')
    event_id:      str          # bookmaker-internal numeric event ID
    market:        str          # market name (e.g. '1X2', 'Over/Under 2.5')
    sport:         str          # 'football', 'basketball', or 'tennis'
    is_live:       bool         # True for in-play bets
    stake:         float        # NGN, rounded to whole naira
    return_if_win: float        # what you receive back if this leg wins


@dataclass
class StakeAllocation:
    legs:              List[LegStake]
    total_stake:       float    # sum of all leg stakes
    guaranteed_return: float    # payout regardless of outcome
    guaranteed_profit: float    # guaranteed_return − total_stake
    profit_pct:        float    # profit as % of total_stake


def calc_from_total(legs: list, total_stake: float) -> StakeAllocation:
    """
    Calculate per-leg stakes for a given total investment.

    legs: list of dicts with keys:
        bookmaker, outcome, odds, odds_key, event_id
    total_stake: total NGN to invest across all legs
    """
    if not legs:
        raise ValueError('legs list is empty')
    if total_stake <= 0:
        raise ValueError('total_stake must be positive')

    inv_sum = sum(1.0 / leg['odds'] for leg in legs)
    if inv_sum >= 1.0:
        raise ValueError(f'No arbitrage: inverse sum = {inv_sum:.4f} >= 1.0')

    result_legs = []
    actual_total = 0.0

    for leg in legs:
        raw_stake = total_stake * (1.0 / leg['odds']) / inv_sum
        s = round(raw_stake)   # round to whole naira
        actual_total += s
        result_legs.append(LegStake(
            bookmaker     = leg['bookmaker'],
            outcome       = leg['outcome'],
            odds          = leg['odds'],
            odds_key      = leg.get('odds_key', ''),
            event_id      = leg.get('event_id', ''),
            market        = leg.get('market', ''),
            sport         = leg.get('sport', 'football'),
            is_live       = leg.get('is_live', False),
            stake         = s,
            return_if_win = round(s * leg['odds'], 2),
        ))

    guaranteed_return = round(actual_total / inv_sum, 2)
    profit = round(guaranteed_return - actual_total, 2)
    profit_pct = round((profit / actual_total) * 100, 3) if actual_total else 0.0

    return StakeAllocation(
        legs              = result_legs,
        total_stake       = actual_total,
        guaranteed_return = guaranteed_return,
        guaranteed_profit = profit,
        profit_pct        = profit_pct,
    )


def calc_from_profit(legs: list, target_profit: float) -> StakeAllocation:
    """
    Back-calculate total stake needed to achieve a desired guaranteed profit.
    """
    if not legs:
        raise ValueError('legs list is empty')
    if target_profit <= 0:
        raise ValueError('target_profit must be positive')

    inv_sum = sum(1.0 / leg['odds'] for leg in legs)
    if inv_sum >= 1.0:
        raise ValueError(f'No arbitrage: inverse sum = {inv_sum:.4f} >= 1.0')

    arb_fraction = 1.0 / inv_sum - 1.0   # profit per unit staked
    total_stake  = target_profit / arb_fraction

    return calc_from_total(legs, total_stake)


def format_allocation(alloc: StakeAllocation) -> str:
    """Return a human-readable summary of the stake allocation."""
    lines = ['', '  ── Stake Allocation ──────────────────────────────']
    for leg in alloc.legs:
        lines.append(
            f'  {leg.bookmaker:<12} {leg.outcome:<8} @ {leg.odds:<6.3f}'
            f'  Stake: ₦{leg.stake:>9,.0f}  →  Returns: ₦{leg.return_if_win:>10,.2f}'
        )
    lines += [
        '  ─────────────────────────────────────────────────',
        f'  Total stake:        ₦{alloc.total_stake:>9,.0f}',
        f'  Guaranteed return:  ₦{alloc.guaranteed_return:>9,.2f}',
        f'  Guaranteed profit:  ₦{alloc.guaranteed_profit:>9,.2f}  ({alloc.profit_pct:.3f}%)',
        '',
    ]
    return '\n'.join(lines)
