"""Declared three-unit single/dual model and funded synthetic replay.

No live provider observations, fees, topups, early profit stop or stake clipping.
Save ev_ledgers.py beside this file for the hash-checked CSV loader.
"""
from decimal import Decimal
from fractions import Fraction
from ev_ledgers import load_rows


def finite_failure(mode, rounds):
    """Initial cash100, fixed total3, failure is inability to fund next3.

    The frozen one-unit remainder is never wagered. Stop after each settlement
    including the last; stopped paths remain in the unconditional population.
    """
    if mode not in ("single", "dual"):
        raise ValueError("mode must be single or dual")
    if isinstance(rounds, bool) or not isinstance(rounds, int) or rounds < 0:
        raise ValueError("rounds must be a nonnegative integer")
    up, flat = (0.485, 0.0) if mode == "single" else (97/300, 97/300)
    state, failed, turnover = {33: 1.0}, 0.0, 0.0
    for _ in range(rounds):
        turnover += 3*sum(state.values())
        following = {}
        for bank, mass in state.items():
            for change, probability in [(1, up), (0, flat), (-1, 1-up-flat)]:
                if not probability:
                    continue
                after = bank+change
                if after < 1:
                    failed += mass*probability
                else:
                    following[after] = following.get(after, 0.0)+mass*probability
        state = following
    return dict(fundingFailure=failed, expectedTurnover=turnover,
                expectedFinalCash=1+3*sum(bank*mass for bank,mass in state.items()))


def replay(rows, mode):
    """Initial100currency units, total3 each flight, all money in integer cents."""
    if mode not in ("single", "dual"):
        raise ValueError("mode must be single or dual")
    balance = peak = 10000
    turnover = gross_total = 0
    failure_after = None
    drawdown = Fraction(0)
    ledger = []
    for row in rows:
        if balance < 300:
            break
        multiplier = Decimal(row['multiplier'])
        gross = (600 if multiplier >= 2 else 0) if mode == "single" else (
            (300 if multiplier >= Decimal('1.5') else 0)
            + (300 if multiplier >= 3 else 0))
        before = balance
        balance += gross-300
        turnover += 300
        gross_total += gross
        peak = max(peak, balance)
        drawdown = max(drawdown, Fraction(peak-balance, peak))
        ledger.append(dict(roundId=int(row['round_id']), beforeCents=before,
                           stakeCents=300, grossCents=gross, afterCents=balance))
        if balance < 300:
            failure_after = int(row['round_id'])
    return dict(mode=mode, wagers=len(ledger), turnoverCents=turnover,
                grossCents=gross_total, finalCents=balance,
                failureAfterRound=failure_after, maxPeakDrawdownPercent=float(100*drawdown)), ledger
