#!/usr/bin/env python3
from pathlib import Path
import json, subprocess, sys, shutil, re
HERE=Path(__file__).resolve().parent
root=HERE if (HERE/'learner').is_dir() else HERE.parent
PINNED='v22.16.0'
checks=[]
def ck(name, cond, detail=''):
    checks.append((name,bool(cond),detail))
def classify(stderr):
    lines=[x.strip() for x in stderr.splitlines() if x.strip()]
    for line in lines:
        if re.search(r'Error \[ERR_[A-Z0-9_]+\]:',line): return line
    for prefix in ('SyntaxError:','TypeError:','ReferenceError:','RangeError:'):
        for line in lines:
            if line.startswith(prefix): return line
    return lines[0] if lines else ''
node=shutil.which('node')
ck('node_available', bool(node), node or '')
node_version=''
if node:
    try: node_version=subprocess.run([node,'--version'],text=True,capture_output=True,check=True).stdout.strip()
    except Exception as e: node_version=f'ERROR:{e}'
ck('node_version_pinned', node_version==PINNED, node_version)
for rel in ['learner/starter/package.json','learner/starter/main.js','learner/starter/local.js','learner/starter/node_modules/demo-pkg/package.json','learner/starter/node_modules/demo-pkg/public.js','learner/transfer/package.json','learner/transfer/main.js','learner/transfer/helper.js','learner/transfer/node_modules/utility-pkg/package.json','learner/evidence/Node_ESM_Trace_v1.template.json']:
    ck('present:'+rel, (root/rel).is_file())
try:
    p=json.loads((root/'learner/starter/package.json').read_text())
    tp=json.loads((root/'learner/transfer/package.json').read_text())
    d=json.loads((root/'learner/starter/node_modules/demo-pkg/package.json').read_text())
    ck('starter_type_explicit', p.get('type') in ('module','commonjs'))
    ck('starter_node_engine_exact', p.get('engines',{}).get('node')=='22.16.0')
    ck('transfer_node_engine_exact', tp.get('engines',{}).get('node')=='22.16.0')
    ck('dependency_exports_present', isinstance(d.get('exports'),dict))
except Exception as e:
    ck('json_parse',False,str(e))
try:
    ev=json.loads((root/'learner/evidence/Node_ESM_Trace_v1.template.json').read_text())
    ck('evidence_schema', ev.get('schema')=='MAKNOW_NODE_ESM_RESOLUTION_TRACE_v1')
    ck('evidence_required_node_pin', ev.get('environment',{}).get('required_node_version')==PINNED)
except Exception as e:
    ck('evidence_schema',False,str(e))
text=(root/'learner/starter/main.js').read_text()
ck('starter_contains_relative_import', "from './" in text)
ck('starter_contains_bare_package_import', "from 'demo-pkg" in text)
if '--self-test' in sys.argv:
    ok=sum(x[1] for x in checks)
    print(f'{ok}/{len(checks)} PASS')
    for n,s,d in checks: print(('PASS' if s else 'FAIL'), n, d)
    raise SystemExit(0 if ok==len(checks) else 1)
if not node or node_version!=PINNED:
    print(json.dumps({'node':node,'observed_node_version':node_version,'required_node_version':PINNED,'error':'PINNED_NODE_VERSION_MISMATCH','structural_checks':f'{sum(x[1] for x in checks)}/{len(checks)}'},ensure_ascii=False,indent=2))
    raise SystemExit(2)
proc=subprocess.run([node,'main.js'],cwd=root/'learner/starter',text=True,capture_output=True)
print(json.dumps({'node':node,'observed_node_version':node_version,'required_node_version':PINNED,'exit_code':proc.returncode,'stdout':proc.stdout.strip(),'stderr_classification':classify(proc.stderr),'stderr_first_line':(proc.stderr.strip().splitlines() or [''])[0],'structural_checks':f'{sum(x[1] for x in checks)}/{len(checks)}'},ensure_ascii=False,indent=2))
