"""Encevra Round 14: exact constructed diagnostics, not model benchmarks.

Python standard library only. Run: python3 diagnostics.py
Writes diagnostic_results.json next to this file. No network or model calls.
"""
from fractions import Fraction as F
from itertools import combinations, product
from pathlib import Path
import json
import math


def fraction(x):
    x = F(x)
    return {"exact": str(x), "decimal": float(x)}


def valid_pairs(values):
    values = frozenset(tuple(v) for v in values)
    if not values or any(len(v) != 2 or any(type(z) is not int or z not in (0, 1) for z in v) for v in values):
        raise ValueError("A nonempty set of binary pairs is required")
    return values


def paired_bounds(items):
    """Sharp finite-cohort bounds if only the supplied per-item constraints apply.
    Pair order is (baseline, candidate). Cross-item constraints are not modeled.
    """
    if not items:
        raise ValueError("Empty cohort")
    ps = [valid_pairs(v) for v in items]
    return (F(sum(min(b-a for a,b in p) for p in ps), len(ps)),
            F(sum(max(b-a for a,b in p) for p in ps), len(ps)))


def transition_bounds(items):
    """Exact DP on allowed (initial, terminal) labels; small offline examples.
    Componentwise extrema need not be achieved by the same completion.
    A possibly-zero denominator is flagged; no zero denominator becomes 1.
    """
    if not items:
        raise ValueError("Empty cohort")
    totals = {(0,0,0)}  # initially wrong, repairs, damage
    for item in items:
        p = valid_pairs(item)
        totals = {(w+(a==0), r+(a==0 and b==1), d+(a==1 and b==0))
                  for w,r,d in totals for a,b in p}
    n = len(items)
    repairs = [F(r,w) for w,r,d in totals if w]
    damages = [F(d,n-w) for w,r,d in totals if w < n]
    return {
        "repair_rate": [min(repairs),max(repairs)] if repairs else None,
        "damage_rate": [min(damages),max(damages)] if damages else None,
        "repair_denominator_can_be_zero": any(w==0 for w,r,d in totals),
        "damage_denominator_can_be_zero": any(w==n for w,r,d in totals),
        "possible_count_states": len(totals),
    }


def flip_budget_bounds(pairs, budget):
    """Exact Hamming-budget sensitivity; a flip means ONE snapshot label.
    Labels are provisionally resolved. All labels are allowed to be mistaken.
    """
    if not pairs or type(budget) is not int or budget < 0:
        raise ValueError("Nonempty cohort and nonnegative integer budget required")
    states = {0: (0,0)}  # cost -> min/max total contrast
    for a,b in pairs:
        valid_pairs([(a,b)])
        nxt = {}
        for used,(lo,hi) in states.items():
            for aa,bb in product((0,1),repeat=2):
                cost = used + (aa!=a) + (bb!=b)
                if cost > budget:
                    continue
                d = bb-aa
                prev = nxt.get(cost)
                new = (lo+d,hi+d)
                nxt[cost] = new if prev is None else (min(prev[0],new[0]),max(prev[1],new[1]))
        states = nxt
    return (F(min(v[0] for v in states.values()),len(pairs)),
            F(max(v[1] for v in states.values()),len(pairs)))


def audit_estimate(q, d, sample):
    if len(q)!=len(d) or not sample or len(set(sample))!=len(sample):
        raise ValueError("Invalid paired audit")
    return sum(q,F(0))/len(q) + sum((d[i]-q[i] for i in sample),F(0))/len(sample)


def audit_envelope(q, allowed, sample, alpha=0.05):
    """Conservative Hoeffding envelope for a simple random audit w/o replacement.
    Conditional on ALL supplied allowed sets containing the reference labels.
    Its probability refers to audit selection, not truth or future-task sampling.
    The caller must establish SRS; this function cannot verify sample selection.
    """
    n = len(q)
    if n!=len(allowed) or not sample or len(set(sample))!=len(sample) or not 0<alpha<1:
        raise ValueError("Invalid audit inputs")
    if any(i<0 or i>=n for i in sample) or any(not -1<=v<=1 for v in q):
        raise ValueError("Invalid audit range")
    ps = [valid_pairs(v) for v in allowed]
    m = len(sample)
    meanq = sum(q,F(0))/n
    lo = meanq + sum((min(b-a for a,b in ps[i])-q[i] for i in sample),F(0))/m
    hi = meanq + sum((max(b-a for a,b in ps[i])-q[i] for i in sample),F(0))/m
    radius = 0.0 if m==n else math.sqrt(8*math.log(2/alpha)/m)
    # Intersection may be empty for unusual samples; do not reverse endpoints.
    lower,upper = max(-1,float(lo)-radius),min(1,float(hi)+radius)
    return {"lower":lower,"upper":upper,"radius":radius,"empty":lower>upper}


def serial(x):
    if isinstance(x,F):return fraction(x)
    if isinstance(x,dict):return {k:serial(v) for k,v in x.items()}
    if isinstance(x,(tuple,list)):return [serial(v) for v in x]
    return x


def main():
    checks=[]
    def check(name, condition):
        if not condition:raise AssertionError(name)
        checks.append(name)
    def rejects(name,fn):
        try:fn()
        except ValueError:checks.append(name)
        else:raise AssertionError(name)

    truth_a=[int(i<80) for i in range(100)]
    truth_b=[int(i<78) for i in range(100)]
    judge_a=truth_a[:]
    judge_b=[int(i<83) for i in range(100)]
    truth_delta=F(sum(truth_b)-sum(truth_a),100)
    judge_delta=F(sum(judge_b)-sum(judge_a),100)
    accuracy=F(sum(a==b for a,b in zip(truth_a+truth_b,judge_a+judge_b)),200)
    specificity=F(37,42)
    pooled_a=(F(80,100)+specificity-1)/specificity
    pooled_b=(F(83,100)+specificity-1)/specificity
    check("high_agreement_can_reverse_effect",(truth_delta,judge_delta,accuracy)==(F(-2,100),F(3,100),F(195,200)))
    check("pooled_correction_fixes_overall_mean_not_difference",(pooled_a+pooled_b)/2==F(158,200) and pooled_b>pooled_a)
    observed=list(zip(judge_a,judge_b))
    sensitivity={b:flip_budget_bounds(observed,b) for b in (0,1,2,3,4,5)}
    check("three_snapshot_label_flips_erase_advantage",sensitivity[3][0]==0)
    check("four_snapshot_label_flips_reverse_advantage",sensitivity[4][0]==F(-1,100))
    check("zero_budget_retains_point",sensitivity[0]==(judge_delta,judge_delta))
    tiny=[(0,1),(1,0),(1,1)]
    for budget in range(7):
        feasible=[]
        for raw in product((0,1),repeat=6):
            pairs=list(zip(raw[::2],raw[1::2]))
            cost=sum(x!=y for p,t in zip(pairs,tiny) for x,y in zip(p,t))
            if cost<=budget:feasible.append(F(sum(b-a for a,b in pairs),3))
        check(f"flip_dp_matches_exhaustive_budget_{budget}",flip_budget_bounds(tiny,budget)==(min(feasible),max(feasible)))

    allpairs=list(product((0,1),repeat=2))
    known=[[(1,1)]]*60+[[(0,0)]]*10+[[(0,1)]]*15+[[(1,0)]]*5
    uncoupled=known+[allpairs]*10
    coupled=known+[[(0,0),(1,1)]]*6+[allpairs]*4
    bu,bc=paired_bounds(uncoupled),paired_bounds(coupled)
    check("unresolved_labels_preserve_full_denominator",bu==(F(0),F(1,5)))
    check("same_artifact_coupling_preserves_uncertainty",bc==(F(3,50),F(7,50)))
    check("coupling_reduces_width_sixty_percent",(bu[1]-bu[0]-(bc[1]-bc[0]))/(bu[1]-bu[0])==F(3,5))
    small=[[(0,0),(1,1)],allpairs,[(0,1)]]
    completions=[F(sum(b-a for a,b in rows),3) for rows in product(*small)]
    check("paired_bounds_are_attained",paired_bounds(small)==(min(completions),max(completions)))
    check("reversing_arms_reverses_bounds",paired_bounds([[(b,a) for a,b in p] for p in coupled])==(-bc[1],-bc[0]))

    # Two joint laws have identical .8 initial and terminal correctness marginals.
    stable=[[(0,0)]]*20+[[(1,1)]]*80
    churn=[[(0,1)]]*20+[[(1,0)]]*20+[[(1,1)]]*60
    st,ct=transition_bounds(stable),transition_bounds(churn)
    check("unchanged_labels_have_no_repair_or_damage",st['repair_rate']==[F(0),F(0)] and st['damage_rate']==[F(0),F(0)])
    check("equal_marginals_do_not_identify_transitions",ct['repair_rate']==[F(1),F(1)] and ct['damage_rate']==[F(1,4),F(1,4)])
    unknown=transition_bounds([allpairs]*3)
    check("zero_denominator_is_explicit",unknown['repair_denominator_can_be_zero'] and unknown['damage_denominator_can_be_zero'])
    check("all_correct_has_null_repair_rate",transition_bounds([[(1,1)]]*2)['repair_rate'] is None)

    q=[F(x) for x in [0,1,0,-1,1,0,0,0]]
    d=[F(x) for x in [0,0,1,-1,0,0,-1,0]]
    samples=list(combinations(range(8),4))
    estimates=[audit_estimate(q,d,s) for s in samples]
    target=sum(d)/8
    residual=[x-y for x,y in zip(d,q)]
    mr=sum(residual)/8
    s2=sum((x-mr)**2 for x in residual)/7
    exact_var=sum((x-target)**2 for x in estimates)/len(estimates)
    check("random_audit_estimator_is_exactly_unbiased",sum(estimates)/len(estimates)==target)
    check("finite_population_variance_matches_enumeration",exact_var==(1-F(4,8))*s2/4)
    allowed=[[(0,int(x))] if x>=0 else [(1,0)] for x in d]
    envelopes=[audit_envelope(q,allowed,s) for s in samples]
    check("conservative_envelope_covers_this_finite_example",all(x['lower']<=target<=x['upper'] for x in envelopes))
    census=audit_envelope(q,allowed,tuple(range(8)))
    check("complete_audit_eliminates_sampling_uncertainty",census['lower']==census['upper']==float(target))
    q100=[F(b-a) for a,b in observed]
    d100=[F(b-a) for a,b in zip(truth_a,truth_b)]
    selected=[i for i,x in enumerate(q100) if x]
    biased=audit_estimate(q100,d100,selected)
    check("disagreement_only_audit_is_not_representative",biased==F(-97,100))
    rejects("empty_cohort_rejected",lambda:paired_bounds([]))
    rejects("empty_allowed_set_rejected",lambda:paired_bounds([[]]))
    rejects("nonbinary_label_rejected",lambda:paired_bounds([[(0,2)]]))
    rejects("duplicate_audit_index_rejected",lambda:audit_estimate(q,d,[0,0]))

    result={
      "round":14,"evidence_status":"Exact calculations on invented labels. No model inference, human annotation, or Encevra performance benchmark.",
      "checks_passed":len(checks),"checks":checks,
      "differential_judge_bias":{"N_tasks":100,"N_snapshot_labels":200,"true_baseline_success":F(4,5),"true_candidate_success":F(39,50),"judged_baseline_success":F(4,5),"judged_candidate_success":F(83,100),"judge_label_accuracy":accuracy,"true_difference":truth_delta,"judged_difference":judge_delta,"pooled_specificity":specificity,"pooled_corrected_baseline":pooled_a,"pooled_corrected_candidate":pooled_b,"pooled_corrected_difference":pooled_b-pooled_a,"flip_sensitivity":sensitivity},
      "unresolved_pair_bounds":{"N":100,"complete_case_difference":F(10,90),"uncoupled":bu,"six_same_artifact_pairs":bc,"relative_width_reduction":F(3,5)},
      "same_marginals":{"initial_correctness":F(4,5),"terminal_correctness":F(4,5),"stable":st,"churn":ct,"independence_implied_repair_rate":F(4,5),"independence_implied_damage_rate":F(1,5)},
      "random_audit":{"N":8,"m":4,"all_subsets":len(samples),"target":target,"mean_estimate":sum(estimates)/len(estimates),"exact_design_variance":exact_var,"census_envelope":census},
      "biased_audit":{"selected_count":len(selected),"estimate_if_naively_treated_as_random":biased,"true_difference":truth_delta},
      "conservative_audit_halfwidths":{"m24":math.sqrt(8*math.log(40)/24),"m96":math.sqrt(8*math.log(40)/96),"interpretation":"Range-only, 95% audit-selection bound before intersection with [-1,1]; not future-task inference."}
    }
    path=Path(__file__).with_name('diagnostic_results.json')
    path.write_text(json.dumps(serial(result),indent=2)+'\n')
    print(json.dumps(serial(result),indent=2))


if __name__=='__main__':main()
