#!/usr/bin/env python3
"""Run the Boot 4 JPA slice using temporary, pinned official test modules."""
import hashlib,json,os,platform,shutil,subprocess,tempfile
from pathlib import Path
from urllib.request import urlopen
from datetime import datetime

ROOT=Path(__file__).resolve().parent
MODULES={'spring-boot-data-jpa-test':'e90ee508484065ded0746344eacf29bc9bd87c9aa52923aebf8535d447e21060',
         'spring-boot-jpa-test':'88fd3ac29a6b49f24917c1e753b47cf2df4e0194461146ad60bde3fb6278f4d4'}
SOURCES=['pom.xml','slice-run.py','slice-src/study/u43/JpaSliceTest.java','slice-src/study/u43/JpaSliceMain.java',
         'src/main/java/study/u43/JpaLab.java','src/main/java/study/u43/model/Account.java','src/main/java/study/u43/model/Board.java','src/main/java/study/u43/model/WorkItem.java','src/main/java/study/u43/model/Department.java','src/main/java/study/u43/model/Employee.java',
         'src/main/java/study/u43/repo/AccountRepository.java','src/main/java/study/u43/repo/AccountView.java','src/main/java/study/u43/repo/EmployeeRepository.java']

def main():
    home=Path(os.environ.get('JAVA_HOME','/Library/Java/JavaVirtualMachines/liberica-jdk-21.jdk/Contents/Home'))
    mvn=shutil.which('mvn'); java=home/'bin/java'; javac=home/'bin/javac'
    if not mvn or not java.exists() or not javac.exists(): raise RuntimeError('需要 JDK 21 和 Maven')
    allow=('PATH','HOME','TMPDIR','LANG','LC_ALL','TZ'); env={k:os.environ[k] for k in allow if k in os.environ}
    env.update(JAVA_HOME=str(home),MAVEN_OPTS='-Xmx384m -XX:ActiveProcessorCount=2')
    java_version=subprocess.check_output([str(java),'-version'],stderr=subprocess.STDOUT,text=True,env=env).strip()
    if '21.0.11' not in java_version: raise RuntimeError('实验基线需要 JDK 21.0.11')
    result={'issue':80,'input':'python3 labs/jpa-u43/slice-run.py','startedAt':datetime.now().astimezone().isoformat(),
            'environment':{'os':platform.platform(),'arch':platform.machine(),'java':java_version},'status':'failed','exitCode':1}
    try:
        with tempfile.TemporaryDirectory(prefix='u43-jpa-slice-') as d:
            tmp=Path(d); jars=[]
            for name,digest in MODULES.items():
                url=f'https://repo.maven.apache.org/maven2/org/springframework/boot/{name}/4.0.9/{name}-4.0.9.jar'
                with urlopen(url,timeout=30) as response: data=response.read()
                if hashlib.sha256(data).hexdigest()!=digest: raise RuntimeError('下载摘要不符: '+name)
                jar=tmp/(name+'.jar'); jar.write_bytes(data); jars.append(str(jar))
            cp=tmp/'classpath.txt'
            subprocess.run([mvn,'-o','-B','-q','compile','org.apache.maven.plugins:maven-dependency-plugin:3.8.1:build-classpath','-DincludeScope=test',f'-Dmdep.outputFile={cp}'],cwd=ROOT,env=env,check=True,capture_output=True,text=True,timeout=180)
            classpath=os.pathsep.join([str(ROOT/'target/classes'),cp.read_text().strip(),*jars])
            classes=tmp/'classes'; classes.mkdir()
            sources=[ROOT/'slice-src/study/u43/JpaSliceTest.java',ROOT/'slice-src/study/u43/JpaSliceMain.java']
            subprocess.run([str(javac),'-cp',classpath,'-d',str(classes),*[str(s) for s in sources]],cwd=ROOT,env=env,check=True,capture_output=True,text=True,timeout=60)
            run=subprocess.run([str(java),'-Dspring.config.location=optional:file:/dev/null','-Xms64m','-Xmx384m','-XX:ActiveProcessorCount=2','-cp',str(classes)+os.pathsep+classpath,'study.u43.JpaSliceMain'],cwd=ROOT,env=env,capture_output=True,text=True,timeout=120)
            result['observations']=[line for line in run.stdout.splitlines() if line.startswith('U43 ')]
            if run.returncode!=0 or 'U43 slice=PASS h2=memory tests=2 rollback=verified non-jpa-component=excluded' not in result['observations']:
                result['diagnostics']=(run.stderr+'\n'+run.stdout)[-5000:]
                raise RuntimeError('JPA slice failed: exit='+str(run.returncode))
            result.update(status='passed',exitCode=0,downloads=[{'name':name,'sha256':digest,'source':f'https://repo.maven.apache.org/maven2/org/springframework/boot/{name}/4.0.9/'} for name,digest in MODULES.items()],
                artifactSha256={p:hashlib.sha256((ROOT/p).read_bytes()).hexdigest() for p in SOURCES},
                limits='H2 2.4.240 内存数据库，切片验证 repository/映射与测试回滚；不验证 MySQL 方言或完整应用。')
    except Exception as exc:
        if isinstance(exc,subprocess.CalledProcessError): result['diagnostics']=(exc.stderr or exc.stdout or '')[-5000:]
        result['error']=type(exc).__name__+': '+(('exit='+str(exc.returncode)) if isinstance(exc,subprocess.CalledProcessError) else str(exc))
        print(json.dumps(result,ensure_ascii=False,indent=2)); raise
    path=ROOT/'evidence/u43-slice-2026-10-31.json'; temp=path.with_suffix('.tmp')
    temp.write_text(json.dumps(result,ensure_ascii=False,indent=2)+'\n'); temp.replace(path)
    print(json.dumps(result,ensure_ascii=False,indent=2))
if __name__=='__main__':main()
