#!/usr/bin/env python3
"""U90 公开入口：30 题编码练习的参考实现与独立对照全部实跑。"""
import hashlib
import json
import os
from pathlib import Path
import platform
import re
import shutil
import subprocess
import tempfile
from datetime import datetime

ROOT = Path(__file__).resolve().parent
EVIDENCE = ROOT / 'evidence/u90-2026-10-31.json'
SOURCES = ['pom.xml', 'README.md', 'run.py',
           'src/main/java/study/u90/Solutions.java', 'src/main/java/study/u90/U90Lab.java']


def diagnostics(output):
    if isinstance(output, bytes):
        output = output.decode('utf-8', 'replace')
    lines = [line for line in (output or '').splitlines()
             if any(x in line for x in ('Exception', 'ERROR', 'AssertionError'))]
    return [line[:400] for line in lines[-6:]]


def main():
    java_home = Path(os.environ.get('JAVA_HOME', '/Library/Java/JavaVirtualMachines/liberica-jdk-21.jdk/Contents/Home'))
    java = java_home / 'bin/java'
    mvn = shutil.which('mvn')
    if not java.is_file() or not mvn:
        raise RuntimeError('需要 JDK 21 和 Maven 3.9')
    env = {key: os.environ[key] for key in ('PATH', 'HOME', 'TMPDIR', 'LANG', 'LC_ALL', 'TZ') if key in os.environ}
    env.update(JAVA_HOME=str(java_home), MAVEN_OPTS='-Xmx512m -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': 127, 'input': 'python3 labs/coding-practice-u90/run.py',
              'startedAt': datetime.now().astimezone().isoformat(),
              'environment': {'os': platform.platform(), 'arch': platform.machine(), 'java': java_version},
              'status': 'failed', 'exitCode': 1, 'observations': []}
    try:
        with tempfile.TemporaryDirectory(prefix='coding-practice-u90-') as directory:
            cp = Path(directory) / 'classpath.txt'
            subprocess.run([mvn, '-o', '-B', '-q', 'compile',
                            'org.apache.maven.plugins:maven-dependency-plugin:3.8.1:build-classpath',
                            '-DincludeScope=runtime', f'-Dmdep.outputFile={cp}'],
                           cwd=ROOT, env=env, check=True, timeout=180, capture_output=True, text=True)
            classpath = str(ROOT / 'target/classes') + os.pathsep + cp.read_text().strip()
            command = [str(java), '-Xms64m', '-Xmx512m', '-XX:ActiveProcessorCount=2',
                       '-cp', classpath, 'study.u90.U90Lab']
            run = subprocess.run(command, cwd=ROOT, env=env, capture_output=True, text=True, timeout=120)
            result['observations'] = [line for line in run.stdout.splitlines() if line.startswith('U90 ')]
            questions = [line for line in result['observations'] if re.match(r'U90 q\d+ .*PASS', line)]
            if run.returncode != 0 or len(questions) != 30 or 'U90 allQuestions passed=30 total=30' not in result['observations']:
                result['diagnostics'] = diagnostics(run.stderr) + diagnostics(run.stdout)
                raise RuntimeError('实验失败或题目未全部通过；exit=' + str(run.returncode)
                                   + '，通过题数=' + str(len(questions)))
            result.update(status='passed', exitCode=0,
                          limits='30 题为文章规格的参考实现与独立对照实跑；未运行性能基准、并发压力与图形化用例；SQL 手写题的主归属在 SQL 手写笔试（SQLite/MySQL 8.4.7 已验证，本票不重复）。',
                          artifactSha256={p: hashlib.sha256((ROOT / p).read_bytes()).hexdigest() for p in SOURCES if (ROOT / p).exists()})
    except Exception as exc:
        if isinstance(exc, subprocess.CalledProcessError):
            result['phase'] = 'maven'
            result['diagnostics'] = diagnostics(exc.stderr) + diagnostics(exc.stdout)
        result['error'] = type(exc).__name__ + ': ' + str(exc)
        raise
    finally:
        if result['status'] == 'passed':
            EVIDENCE.parent.mkdir(parents=True, exist_ok=True)
            tmp = EVIDENCE.with_suffix('.tmp')
            tmp.write_text(json.dumps(result, ensure_ascii=False, indent=2) + '\n')
            tmp.replace(EVIDENCE)
        else:
            print(json.dumps(result, ensure_ascii=False, indent=2))
    print(json.dumps(result, ensure_ascii=False, indent=2))


if __name__ == '__main__':
    main()
