"""Independent re-implementation of the assessment and the funded cycle (own DP on a dict lattice, own float MC,
no use of eval_chain/funded_chain), compared with prime.eval_chain / prime.funded_chain; then wallet_mc against the chains
(cash per purchase, purchases, at p_paid = 1, deep wallet). All at the deployed 'random side, swap charged' cell."""
import time, numpy as np
from pa_imp import *
from modules import hedge as HG
g=PA.cost_share(34.791728647093755)+0.004783927673690548
risk=0.03; c=g*risk; D=0.09; T=0.09
U=40/c                     # lattice units per bankroll: one round trip = 40 units
iC=40; iR=round(risk*U); iD=round(D*U); iT=round(T*U)
# ---------- independent assessment DP (dict) ----------
def eval_dp():
    v={0:1.0}; ppass=0.0; ptr=0.0; fail=0.0
    n=0
    while v and n<5000:
        n+=1; nv={}
        for s,p in v.items():
            a=min(iR,max(1,iT-s+iC)); b=min(iR,max(1,s+iD-iC)); pw=b/(a+b)
            for (ds,pr,win) in ((a-iC,pw,True),(-b-iC,1-pw,False)):
                t=s+ds
                if win and t>=iT: ppass+=p*pr; ptr+=p*pr*n
                elif (not win) and t<=-iD: fail+=p*pr; ptr+=p*pr*n
                else: nv[t]=nv.get(t,0)+p*pr
        v={k:x for k,x in nv.items() if x>1e-16}
    return ppass,fail,ptr
t0=time.time(); pp,pf,et=eval_dp()
ref=PA.eval_chain(risk,c,rr=1.0,clip_up=True,clip_dn=True)
print(f"assessment: independent DP pass {pp:.8f} fail {pf:.8f} E[trades] {et:.5f}  | eval_chain pass {ref['p_pass']:.8f} fail {ref['p_fail']:.8f} E[trades] {ref['e_trades']:.5f}  ({time.time()-t0:.0f}s)")
# ---------- independent float MC for the assessment ----------
rng=np.random.default_rng(2)
n=5000; eq=np.zeros(n); done=np.zeros(n,bool); passed=np.zeros(n,bool); tr=np.zeros(n)
while not done.all():
    a=np.minimum(risk,T-eq+c); b=np.minimum(risk,eq+D-c); a=np.maximum(a,1e-12); b=np.maximum(b,1e-12)
    win=rng.random(n)<b/(a+b)
    step=np.where(win,a,-b)-c
    eq=np.where(done,eq,eq+step); tr+=~done
    newp=(~done)&(eq>=T-1e-9); newd=(~done)&(eq<=-D+1e-9)
    passed|=newp; done|=newp|newd
print(f"assessment: float MC (5000) pass {passed.mean():.4f} ± {np.sqrt(passed.mean()*(1-passed.mean())/n):.4f}  E[trades] {tr.mean():.2f}")
# ---------- independent funded cycle DP ----------
def funded_dp(rf,wait,split=0.7,B=3000):
    cf=g*rf; Uf=40/cf; iCf=40; iRf=round(rf*Uf); iDf=round(D*Uf)
    M=int(np.ceil(max(100/split/B, rf/0.35)*Uf-1e-9))
    v={0:1.0}; pay=0.0; die=0.0; paysize=0.0; firstpay_pmf={}
    for t in range(1,20000):
        nv={}
        for s,p in v.items():
            b=min(iRf,max(1,s+iDf-iCf)); pw=b/(iRf+b)
            if s-b-iCf<=-iDf: die+=p*(1-pw)
            else: nv[s-b-iCf]=nv.get(s-b-iCf,0)+p*(1-pw)
            nv[s+iRf-iCf]=nv.get(s+iRf-iCf,0)+p*pw
        if t>=wait:
            for s in [k for k in nv if k>=M]:
                p=nv.pop(s); pay+=p; paysize+=p*s/Uf; firstpay_pmf[t]=firstpay_pmf.get(t,0)+p
        v={k:x for k,x in nv.items() if x>1e-15}
        if not v: break
    K=pay/(1-pay)
    cum=0; med=None
    for t in sorted(firstpay_pmf):
        cum+=firstpay_pmf[t]
        if cum>=0.5*pay: med=t; break
    return dict(p_any=pay,e_W=K*paysize/pay,med=med)
rf=0.01575
for wait in (7,):
    t0=time.time(); d=funded_dp(rf,wait)
    ref=PA.funded_chain(rf,g*rf,PA.payout_threshold(rf,1.0,3000,0.7),rr=1.0,clip_dn=True,wait=wait)
    print(f"funded rf={rf} wait={wait}: independent DP p_any {d['p_any']:.8f} E[W] {d['e_W']:.6f} med first pay {d['med']} | funded_chain p_any {ref['p_any']:.8f} E[W] {ref['e_W']:.6f} med {ref['med_first_pay']}  ({time.time()-t0:.0f}s)")
