#!/usr/bin/env python3
"""
gen_full_flow_batch.py
对已有 03_参数定义.yaml 的接口批量执行完整 CPP 生成链:
  st_to_fuzz_config → gen_fuzz_cpp(normal) → gen_non_contig_from_normal →
  gen_error_scenarios+gen_error_cpp → gen_consistent_from_normal → gen_multithread_from_nc
并逐个编译校验(-fsyntax-only)。

用法:
  python gen_full_flow_batch.py --apis <清单文件>   # 每行一个 aclnnApiName
  python gen_full_flow_batch.py --api aclnnXxx
"""
import argparse
import os
import subprocess
import sys

ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
GEN = os.path.join(ROOT, "skills/ascendc-fuzz-cpp-gen/scripts")
CONS = os.path.join(ROOT, "skills/gen-consistent-from-normal/scripts")
ASCEND = "/usr/local/Ascend/ascend-toolkit/latest/x86_64-linux"


def sh(cmd, timeout=600):
    r = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout, cwd=ROOT)
    return r.returncode, (r.stdout + r.stderr)


def compile_check(cpp):
    cmd = ["g++", "-fsyntax-only", "-w", "-DAscend950DT_9582",
           "-I", "turing_sec/aclnnAPI_fuzz/inc/utils/",
           "-I", "turing_sec/aclnnAPI_fuzz/fuzzlib/",
           "-I", "turing_sec/aclnnAPI_fuzz/inc/acl/",
           "-I", ASCEND + "/include/",
           "-I", ASCEND + "/x86_64-linux/include/aclnnop/",
           "-I", ASCEND + "/include", "-std=c++11", "-pthread", cpp]
    rc, out = sh(cmd)
    errs = [l for l in out.splitlines() if "error:" in l]
    return len(errs), errs[:3]


def process(api):
    d = os.path.join(ROOT, "output", api)
    td = os.path.join(d, "test-design")
    y03 = os.path.join(td, "03_参数定义.yaml")
    if not os.path.isfile(y03):
        return f"SKIP: 无 03_参数定义.yaml"
    cfg = os.path.join(td, "fuzz_config.yaml")
    # 1) config
    rc, out = sh(["python3", os.path.join(GEN, "st_to_fuzz_config.py"),
                  "--param_def", y03, "--op_name", api, "--output", cfg])
    if not os.path.isfile(cfg):
        return f"FAIL st_to_fuzz_config: {out[-200:]}"
    # 2) normal
    rc, out = sh(["python3", os.path.join(GEN, "gen_fuzz_cpp.py"),
                  "--op_name", api, "--config", cfg, "--output", d])
    normal = os.path.join(d, f"{api}.cpp")
    if not os.path.isfile(normal):
        return f"FAIL gen_fuzz_cpp: {out[-200:]}"
    # 3) non_contig
    nc = os.path.join(d, f"{api}_non_contig.cpp")
    sh(["python3", os.path.join(GEN, "gen_non_contig_from_normal.py"), normal, nc, api])
    # 4) error
    es = os.path.join(td, "error_scenarios.yaml")
    sh(["python3", os.path.join(GEN, "gen_error_scenarios.py"), "--param_yaml", y03, "--output", es])
    ecp = os.path.join(d, f"{api}_error.cpp")
    sh(["python3", os.path.join(GEN, "gen_error_cpp.py"), "--op_name", api,
        "--scenarios", es, "--param_yaml", y03, "--output", ecp])
    # 5) consistent
    cst = os.path.join(d, f"{api}_consistent.cpp")
    sh(["python3", os.path.join(CONS, "gen_consistent_from_normal.py"),
        "--input", normal, "--output", cst, "--api", api])
    # 6) multithread
    mt = os.path.join(d, f"{api}_multithread.cpp")
    sh(["python3", os.path.join(ROOT, "scripts/gen_multithread_from_nc.py"), nc, mt, api])
    # 编译校验
    results = {}
    for name, p in [("normal", normal), ("nc", nc), ("mt", mt), ("error", ecp), ("consistent", cst)]:
        if os.path.isfile(p):
            n, errs = compile_check(os.path.relpath(p, ROOT))
            results[name] = n
            if n:
                results[name] = f"{n}({' | '.join(e.split(': error:')[0].split('/')[-1] for e in errs)})"
        else:
            results[name] = "缺文件"
    ok = all(isinstance(v, int) and v == 0 for v in results.values())
    return ("OK " if ok else "ERR ") + " ".join(f"{k}={v}" for k, v in results.items())


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--apis")
    ap.add_argument("--api")
    args = ap.parse_args()
    apis = [args.api] if args.api else [l.strip() for l in open(args.apis) if l.strip()]
    for i, api in enumerate(apis, 1):
        r = process(api)
        print(f"[{i}/{len(apis)}] {api}: {r}", flush=True)


if __name__ == "__main__":
    main()