"""Exact independent motif checker. Acceptance does not certify minimality."""
from fractions import Fraction
import json, sys
from pathlib import Path

def check(d):
    L,P=d['left'],d['right']
    if not isinstance(L,list) or not L or not isinstance(P,list) or len(P)!=len(L):
        raise ValueError('Nonempty matching entity rows required')
    m=len(L)
    if not isinstance(L[0],list) or not L[0]: raise ValueError('Nonempty reaction columns required')
    n=len(L[0])
    for rows in (L,P):
        if any(not isinstance(row,list) or len(row)!=n for row in rows): raise ValueError('Matrix shape mismatch')
        if any(type(a) is not int or a<0 for row in rows for a in row): raise ValueError('Coefficients must be nonnegative integers')
    X,S=d['entities'],d['reactions']
    for inds,size in ((X,m),(S,n)):
        if not isinstance(inds,list) or not inds or any(type(i) is not int or not 0<=i<size for i in inds): raise ValueError('Invalid support')
        if len(set(inds))!=len(inds): raise ValueError('Duplicate support index')
    values=d['flow']
    if len(values)!=n or any(type(x) not in (int,str) for x in values): raise ValueError('Use exact integer or rational-string flows')
    v=[Fraction(x) for x in values]
    reasons=[]
    if any(v[r] for r in range(n) if r not in S): reasons.append('Flow outside selected reactions')
    for r in S:
        if not any(L[x][r]>0 for x in X) or not any(P[x][r]>0 for x in X): reasons.append(f'Reaction {r} fails literal two-sided admissibility')
    production=[sum((Fraction(P[x][r]-L[x][r])*v[r] for r in range(n)),Fraction(0)) for x in range(m)]
    if any(production[x]<=0 for x in X): reasons.append('Internal production is not strictly positive')
    return dict(accepted=not reasons,certificate='motif; PAC existence follows by finite descent' if not reasons else 'rejected candidate',minimality='not checked',production=list(map(str,production)),reasons=reasons)

if __name__=='__main__':
    try:
        result=check(json.loads(Path(sys.argv[1]).read_text(encoding='utf-8')))
        print(json.dumps(result,indent=2))
        raise SystemExit(0 if result['accepted'] else 1)
    except (ValueError,KeyError,IndexError,TypeError,ZeroDivisionError) as e:
        print(json.dumps(dict(accepted=False,error=str(e))))
        raise SystemExit(2)
