"""Paper-specific witness replay and operational accounting."""
from fractions import Fraction as F
from pathlib import Path
import json,math
import paper_checks as cp
from reactor import EdgeKinetics,PhosphorylationNetwork,QuadraticMemoryContract


def load(name):return json.loads((Path(__file__).parent/name).read_text())


class ExactPaperReplay:
    def run(self):
        cp.NCHECK=0;cp.REPORT={};cp.FULL=True
        result=cp.main()
        return {k:v for k,v in result.items() if 'seconds' not in k}


class PublishedSource:
    def __init__(self,loading_kernel_shift=F(0),clock_multiplier=F(1),reverse_activity=F(0)):
        data=load('postproof_candidate_interface.json')
        p=[F(x)+loading_kernel_shift*10*k for x,k in zip(data['p'],cp.UP)]
        q=[F(x)+loading_kernel_shift*k for x,k in zip(data['q'],cp.DOWN)]
        if min(p+q)<=0:raise ValueError('kernel shift produced a nonpositive loading')
        self.p,self.q=p,q
        rates=[EdgeKinetics(a+k,F(1),F(k)/a,b+l,F(1),F(l)/b).scaled(clock_multiplier) for a,b,k,l in zip(p,q,cp.UP,cp.DOWN)]
        self.network=PhosphorylationNetwork.cube(3,rates,reverse_activity)
        self.totals=(F(10),F(1),F(cp.ST))


class PublishedOperatingContract:
    def calculate(self,size_multiplier=F(1),clock_multiplier=F(1)):
        size_multiplier,clock_multiplier=F(size_multiplier),F(clock_multiplier)
        if min(size_multiplier,clock_multiplier)<=0:raise ValueError('positive budget and clock multipliers required')
        op=load('postproof_candidate_operating.json');loc=load('postproof_candidate_local_certificate.json')
        recovery=F(op['Trec'])/clock_multiplier;storage=100*recovery
        baseline=int(op['Omega']);volume=math.ceil(baseline*size_multiplier)
        rows=[];required=F(1)
        for label,local in zip(op['labels'],loc['labels']):
            c=QuadraticMemoryContract(F(label['pmax']),F(label['v_exit']),F(label['lambda_']),F(local['local_C']),31).rescale_clock(clock_multiplier)
            bound=c.sufficient_size(recovery,storage);required=max(required,bound)
            ret,rec,composite=c.failures(volume,recovery,storage)
            rows.append(dict(label=label['index'],required_size=bound,retention_failure_upper=ret,recovery_failure_upper=rec,composite_failure_upper=composite,certificate_informative=composite<1))
        return dict(system_size=volume,required_size=required,sufficient_size_passes=volume>=required,recovery_time=recovery,storage_horizon=storage,rows=rows,
            scope='Local recovery then continuous retention; sufficient bounds, not estimates of minimum resources. Clock scaling preserves the matched budget. No writing protocol or reversible-source finite-count contract is asserted.')


def driving_ratios(network):
    """Local detailed-balance constants for the reversible extension at unit activities."""
    rows=[]
    for i,r in enumerate(network.kinetics):
        d=r.association*r.catalysis/r.dissociation;h=r.reverse_association*r.reverse_catalysis/r.reverse_dissociation
        assert r.catalysis/d==r.dissociation/r.association
        assert r.reverse_catalysis/h==r.reverse_dissociation/r.reverse_association
        rows.append(dict(edge=i,kinase_reverse=d,phosphatase_reverse=h,kinase_binding_ratio=r.association/r.dissociation,kinase_catalytic_ratio=r.catalysis/d,phosphatase_binding_ratio=r.reverse_association/r.reverse_dissociation,phosphatase_catalytic_ratio=r.reverse_catalysis/h))
    return rows
