from fractions import Fraction as Q
from itertools import product
from functools import lru_cache
import json

MODULE_ID = 'AME-PHRONESIS-001'
MODULE_VERSION = '0.1-design-candidate'
D = Q(9, 10)
U = Q(2, 3)


def fmt(x):
    return {'exact': str(x), 'decimal': float(x)}

# -----------------------------
# View 1: Fixed-policy friction
# -----------------------------
def matrix(m):
    return ((Q(2,5), Q(1,10)+m/5),
            (Q(1,10)+m/5, Q(2,5)))

def step(z, m, replaced=False):
    a = matrix(m)
    u = Q(0) if replaced else m/10
    return tuple(sum(a[i][j]*z[j] for j in range(2)) + u for i in range(2))

def fixed_restraint_advantage(n, m, replaced=False):
    z = (Q(0), Q(0)); loss = Q(0); gain = Q(0)
    for t in range(n):
        z = step(z, m, replaced)
        loss += D**t * sum(z)
        gain += D**t * m/2
    return loss - gain

def fixed_infinite_advantage(m):
    r = Q(1,2) + m/5
    return m/(1-D) * (Q(1,5)/(1-D*r) - Q(1,2))

def fixed_stationary_advantage(m):
    r = Q(1,2) + m/5
    return m/5/(1-r) - m/2

# -----------------------------
# View 2: Adaptive switching
# Exact endpoint envelope under original alpha=0 model.
# -----------------------------
def transition(s, m):
    return (Q(1,2)+m/5)*s + m/5

def simulate(seq, s=Q(0)):
    total = Q(0)
    for t, m in enumerate(seq):
        m = Q(m)
        s = transition(s, m)
        total += D**t * (m/2 - s)
    return total, s

def envelope(lines):
    unique = {}
    for a,b,seq in lines:
        if a not in unique or b > unique[a][0] or (b == unique[a][0] and seq < unique[a][1]):
            unique[a] = (b, seq)
    hull=[]; starts=[]
    for a,(b,seq) in sorted(unique.items()):
        start = None
        while hull:
            pa,pb,_ = hull[-1]
            start = (pb-b)/(a-pa)
            if len(hull)>1 and start <= starts[-1]:
                hull.pop(); starts.pop()
            else:
                break
        if not hull:
            start = None
        hull.append((a,b,seq)); starts.append(start)
    kept=[]
    for i,line in enumerate(hull):
        left=starts[i]; right=starts[i+1] if i+1<len(hull) else None
        if (right is None or right >= 0) and (left is None or left <= U):
            kept.append(line)
    return kept

def backup(lines):
    candidates=[]
    for m in (0,1):
        r=Q(1,2)+Q(m,5); c=Q(m,5)
        for a,b,seq in lines:
            candidates.append((r*(D*a-1), Q(m,2)-c+D*(a*c+b), (m,)+seq))
    return envelope(candidates)

def build_stages(max_horizon=200):
    stages=[[(Q(0),Q(0),())]]
    for _ in range(1,max_horizon+1):
        stages.append(backup(stages[-1]))
    return stages

STAGES = build_stages(200)

def select(lines, s=Q(0)):
    return max(lines, key=lambda x:(x[0]*s+x[1], tuple(-m for m in x[2])))

def adaptive_value(n, s=Q(0)):
    if not (0 <= n <= 200):
        raise ValueError('design candidate certifies horizons 0..200 only')
    if not (Q(0) <= s <= U):
        raise ValueError('state must lie in [0,2/3]')
    a,b,seq = select(STAGES[n], s)
    return a*s+b, seq, len(STAGES[n])

# -----------------------------
# Validation witness: nonlinear action counterexample (Appendix F)
# Not a public multi-period calculator.
# -----------------------------
def nonlinear_witness():
    s, alpha = Q(0), Q(1,5)
    c = Q(3,10)-s/5
    m = c/(2*alpha)
    def reward(x):
        return -s/2 + c*x - alpha*x*x
    return {
        's': fmt(s), 'alpha': fmt(alpha), 'm_star': fmt(m),
        'reward_star': fmt(reward(m)), 'reward_0': fmt(reward(Q(0))),
        'reward_1': fmt(reward(Q(1))),
        'interior_advantage': fmt(reward(m)-max(reward(Q(0)),reward(Q(1))))
    }

# -----------------------------
# View 3: Continuous-action leak witness from Appendix G
# Default exact witness only. Binary defense model itself stays separate.
# -----------------------------
DEF_T = 8

def defense_f(s,m): return (Q(1,2)+m/5)*s+m/5

def defense_solve(p, fixed=None):
    T = DEF_T
    def outside(t):
        return p['outside'] * sum((D**j for j in range(T-t)), Q(0))
    @lru_cache(None)
    def value(t,s,pending):
        if t == T:
            return -p['loss'] if pending else Q(0)
        choices=(Q(fixed[t]),) if fixed is not None else (Q(0),Q(1))
        vals=[]
        for m in choices:
            sp=defense_f(s,m)
            cost=p['cost']*m*(t+1)**p['power']
            reward=m/2-sp-cost
            if pending:
                v=reward-p['loss']+D*outside(t+1)
            else:
                hazard=p['enforce']*(p['detect'] if sp>p['crit'] else p['false_alarm'])
                hit=(D*value(t+1,sp,True) if p['delay'] else -p['loss']+D*outside(t+1))
                v=reward+(1-hazard)*D*value(t+1,sp,False)+hazard*hit
            vals.append(v)
        return max(vals)
    return value(0,Q(0),False)

BASE_DEFENSE=dict(crit=Q(19,100), detect=Q(0), enforce=Q(1), false_alarm=Q(0),
                  delay=0, loss=Q(1), outside=Q(0), cost=Q(0), power=0)

def continuous_action_leak_witness():
    p = BASE_DEFENSE | {'detect':Q(1)}
    m = Q(1,10)
    seq=(m,)*DEF_T
    val=defense_solve(p, seq)
    s=Q(0); states=[]
    for _ in range(DEF_T):
        s=defense_f(s,m); states.append(s)
    binary_best=defense_solve(p)
    binary_rest=defense_solve(p,(0,)*DEF_T)
    return {
        'horizon': DEF_T,
        'm': fmt(m),
        'trigger': fmt(p['crit']),
        'max_state': fmt(max(states)),
        'all_states_below_trigger': all(x <= p['crit'] for x in states),
        'binary_best_advantage_over_restraint': fmt(binary_best-binary_rest),
        'small_action_value': fmt(val),
        'claim': 'Witness only: binary-action deterrence does not establish continuous-action deterrence.'
    }

# -----------------------------
# View 4: Combined friction accounting condition (Section 7)
# -----------------------------
def combined_friction_accounting(delta_f_total, gross_benefit_difference, direct_cost_difference):
    lhs = Q(delta_f_total)
    rhs = Q(gross_benefit_difference) + Q(direct_cost_difference)
    margin = lhs-rhs
    if margin > 0:
        result = 'restraint_preferred_under_declared_accounting'
    elif margin < 0:
        result = 'higher_control_preferred_under_declared_accounting'
    else:
        result = 'tie_under_declared_accounting'
    return {
        'incremental_friction': fmt(lhs),
        'gross_benefit_difference_BA_minus_BR': fmt(Q(gross_benefit_difference)),
        'direct_cost_difference_CR_minus_CA': fmt(Q(direct_cost_difference)),
        'required_threshold': fmt(rhs),
        'margin': fmt(margin),
        'result': result,
        'boundary': 'Accounting condition only; supplied component values are not empirical evidence.'
    }

# -----------------------------
# Regression gates
# -----------------------------
def run_regressions():
    checks=[]
    def check(name, cond, detail=None):
        if not cond:
            raise AssertionError(name)
        checks.append({'name':name,'passed':True,'detail':detail})

    # Appendix D invariants and thresholds
    check('D one-period maximal manipulation profitable', fixed_restraint_advantage(1,Q(1)) < 0)
    check('D fifty-period maximal manipulation self-penalizing', fixed_restraint_advantage(50,Q(1)) > 0)
    check('D stationary threshold m=1/2', fixed_stationary_advantage(Q(1,2)) == 0)
    check('D discounted lifetime threshold m=5/6', fixed_infinite_advantage(Q(5,6)) == 0)
    check('D rankings differ at m=3/4', fixed_stationary_advantage(Q(3,4)) > 0 and fixed_infinite_advantage(Q(3,4)) < 0)

    # Appendix E core adverse result
    v50, seq50, seg50 = adaptive_value(50,Q(0))
    check('E maximal constant policy loses at T=50', simulate((1,)*50)[0] < 0)
    check('E adaptive optimum positive at T=50', v50 > 0)
    pulse = Q(3,22)
    check('E pulse witness exact 3/22', (Q(3,10)-Q(1,5)*(D/2)/(1-D/2)) == pulse and pulse > 0)
    v200, _, _ = adaptive_value(200,Q(0))
    tail = Q(1,3)*D**200/(1-D)
    check('E infinite value lower bound positive', v200-tail > 0)

    # Appendix F scope-break witness
    nw = nonlinear_witness()
    check('F interior m*=3/4', nw['m_star']['exact'] == '3/4')
    check('F reward*=9/80', nw['reward_star']['exact'] == '9/80')
    check('F interior advantage=1/80', nw['interior_advantage']['exact'] == '1/80')

    # Appendix G continuous-action leak witness
    cw = continuous_action_leak_witness()
    check('G binary reliable-response advantage is zero', cw['binary_best_advantage_over_restraint']['exact'] == '0')
    check('G small action stays below trigger', cw['all_states_below_trigger'])
    check('G m=0.1 witness positive', Q(cw['small_action_value']['exact']) > 0)
    check('G exact m=0.1 witness value preserved', cw['small_action_value']['exact'] == '537684079808499879/6103515625000000000')

    # Combined accounting identity sanity
    c = combined_friction_accounting(Q(3),Q(2),Q(0))
    check('COMB positive margin classifies restraint', c['result']=='restraint_preferred_under_declared_accounting')

    return {
        'module_id':MODULE_ID,
        'module_version':MODULE_VERSION,
        'status':'PASS',
        'checks':checks,
        'passed':len(checks),
        'reference_outputs':{
            'fixed_T50_m1':fmt(fixed_restraint_advantage(50,Q(1))),
            'adaptive_T50_s0':fmt(v50),
            'adaptive_T50_sequence':''.join(map(str,seq50)),
            'adaptive_T50_value_segments':seg50,
            'nonlinear_witness':nw,
            'continuous_action_leak':cw,
            'combined_accounting_example':c,
        },
        'boundaries':{
            'empirical_validation':False,
            'independent_specialist_peer_review':False,
            'deployment_certification':False,
            'continuous_action_global_optimum_in_defense_extension_certified':False,
            'nonlinear_multi_period_solver_certified':False,
            'source_bindings_modified':False,
            'master_hash_manifest_v17_modified':False,
            'master_hash_manifest_v18_created':False,
        }
    }

if __name__ == '__main__':
    print(json.dumps(run_regressions(), indent=2))
