#!/usr/bin/env python3
"""Run U47 Spring Integration in-process; record only synthetic observations."""
import hashlib
import json
import os
from pathlib import Path
import platform
import re
import shutil
import subprocess
import tempfile
import uuid
from datetime import datetime

ROOT = Path(__file__).resolve().parent
EVIDENCE = ROOT / 'evidence/u47-2026-10-31.json'
SOURCES = ['pom.xml', 'README.md', 'run.py', 'src/main/java/study/u47/U47Lab.java']
REQUIRED_JARS = ['spring-integration-core-7.0.7.jar', 'spring-messaging-7.0.10.jar', 'spring-context-7.0.10.jar']
MARKERS = ['directChannel ', 'transformer ', 'queueChannel ', 'retry attempts=', 'retryExhausted ', 'advice ']


def diagnostics(output):
    if isinstance(output, bytes):
        output = output.decode('utf-8', 'replace')
    output = output or ''
    lines = [line for line in output.splitlines() if any(x in line for x in ('Exception', 'ERROR', 'Caused by:', 'AssertionError'))]
    return [line[:500] 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')
    allowed = ('PATH', 'HOME', 'TMPDIR', 'LANG', 'LC_ALL', 'TZ')
    env = {key: os.environ[key] for key in allowed if key in os.environ}
    env.update(JAVA_HOME=str(java_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': 84, 'input': 'python3 labs/spring-integration-u47/run.py',
              'startedAt': datetime.now().astimezone().isoformat(),
              'environment': {'os': platform.platform(), 'arch': platform.machine()}, 'status': 'failed', 'exitCode': 1,
              'observations': []}
    run_id = 'u47_' + uuid.uuid4().hex[:12]
    result['runId'] = run_id
    result['resourceNote'] = '纯进程内实验：无外部服务、无持久化资源；AnnotationConfigApplicationContext 关闭即结束。'
    try:
        with tempfile.TemporaryDirectory(prefix='spring-integration-u47-') as directory:
            cp = Path(directory) / 'classpath.txt'
            cmd = [mvn, '-o', '-B', '-q', 'compile', 'org.apache.maven.plugins:maven-dependency-plugin:3.8.1:build-classpath',
                   '-DincludeScope=runtime', f'-Dmdep.outputFile={cp}']
            subprocess.run(cmd, cwd=ROOT, env=env, check=True, timeout=180, capture_output=True, text=True)
            classpath = str(ROOT / 'target/classes') + os.pathsep + cp.read_text().strip()
            versions = [x for x in cp.read_text().split(os.pathsep)
                        if any(k in x for k in ['/spring-integration-core/', '/spring-messaging/', '/spring-context/'])]
            result['dependencies'] = [Path(x).name for x in versions]
            for required in REQUIRED_JARS:
                if not any(required in d for d in result['dependencies']):
                    raise RuntimeError('依赖版本不符: ' + required + '; actual=' + str(result['dependencies']))
            command = [str(java), '-Dspring.config.location=optional:file:/dev/null', '-Xms64m', '-Xmx256m',
                       '-XX:ActiveProcessorCount=2', '-cp', classpath, 'study.u47.U47Lab']
            returncode = None
            result['phase'] = 'java-lab'
            stderr = ''
            try:
                run = subprocess.run(command, cwd=ROOT, env=env, capture_output=True, text=True, timeout=120)
                stdout, stderr, returncode = run.stdout, run.stderr, run.returncode
            except subprocess.TimeoutExpired as exc:
                stdout = (exc.stdout or b'').decode('utf-8', 'replace') if isinstance(exc.stdout, bytes) else (exc.stdout or '')
                stderr = exc.stderr or ''
            result['observations'] = [line for line in stdout.splitlines() if line.startswith('U47 ')]
            if returncode != 0 or not all(any(line.startswith('U47 ' + m) for line in result['observations']) for m in MARKERS):
                result['diagnostics'] = diagnostics(stderr) + diagnostics(stdout)
                raise RuntimeError('实验进程失败或观察缺失；exit=' + str(returncode))
            result.update(status='passed', exitCode=0, java=java_version,
                          limits='同进程消息流；未运行 JMS/HTTP 等真实适配器、跨进程通道、持久化队列与生产容量；重试次数语义为本组合观察。',
                          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()
