"""Shared candidate priors and conservative unphased decoding for LD ablations."""
import collections,math
from endpoints import numeric_four

def candidate_prior(identities,training_cores,alpha=1.0):
    if alpha<=0 or not identities or len(set(identities))!=len(identities) or not training_cores:raise ValueError('Invalid candidate prior')
    counts=collections.Counter(training_cores)
    if not set(counts)<=set(identities):raise ValueError('Training candidate missing')
    unknown=[x for x in identities if x not in counts]
    mass=[counts[x]+alpha if x in counts else alpha/len(unknown) for x in identities]
    # The single unseen-category mass is shared across outside-template candidates.
    # If none exist, condition on the available candidate catalogue.
    total=math.fsum(mass)
    return [x/total for x in mass]

def decode(marginal,candidates,tolerance=1e-12):
    n=len(candidates)
    if len(marginal)!=n or any(len(x)!=n for x in marginal):raise ValueError('Marginal shape mismatch')
    scores=[(marginal[i][j]+(marginal[j][i] if i!=j else 0),i,j) for i in range(n) for j in range(i,n)]
    peak=max(x[0] for x in scores);pairs=[(i,j) for p,i,j in scores if peak-p<=tolerance]
    named=[];core_counts=[]
    for i,j in pairs:
        pair=[];cores=collections.Counter()
        for index in [i,j]:
            c=candidates[index];labels={numeric_four(x) for x in c['labels']}
            pair.append(next(iter(labels)) if not c['label_unknown'] and len(labels)==1 and None not in labels else None)
            if len(c['core_ids'])==1:cores[c['core_ids'][0]]+=1
        named.append(tuple(sorted(pair)) if None not in pair else None);core_counts.append(cores)
    canonical=named[0] if named and named[0] is not None and all(x==named[0] for x in named) else None
    common=core_counts[0].copy()
    for counts in core_counts[1:]:common &= counts
    shared=sorted(common.elements());assert len(shared)<=2
    calls=[{'labels':[canonical[i]] if canonical else [],'label_unknown':canonical is None,
            'cores':[shared[i]] if i<len(shared) else [],'core_unknown':i>=len(shared)} for i in range(2)]
    return {'slots':calls,'best_candidate_pairs':pairs,'unphased_pair_score':peak,'tied_pairs':len(pairs),'confidence_calibrated':False}
