#!/usr/bin/env python3
"""
AVM Dataset Panel — Cross-Language Dispatcher

Runs each language's existing AVM test harness and reports pass/fail.
Uses language-specific test runners.
"""

import subprocess
import sys
import os
import re
from typing import Dict, Optional, Tuple, Callable

ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))


# ── Helper ──────────────────────────────────────────────────────────

def _run(cmd: list, cwd: str = ROOT, timeout: int = 60) -> dict:
    try:
        result = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True, timeout=timeout)
        return {"rc": result.returncode, "out": result.stdout, "err": result.stderr}
    except FileNotFoundError:
        return {"rc": -1, "out": "", "err": "not_found"}
    except subprocess.TimeoutExpired:
        return {"rc": -1, "out": "", "err": "timeout"}
    except Exception as e:
        return {"rc": -1, "out": "", "err": str(e)}


# ── Per-language test runners ─────────────────────────────────────
# Each returns (passes: int, fails: int, note: str)

def run_python() -> Tuple[int, int, str]:
    test = os.path.join(ROOT, "tests", "test_avm_python.py")
    if not os.path.exists(test):
        return 0, 0, "test file missing"
    r = _run([sys.executable, test])
    # Count "✅ ..." lines = passes
    passes = r["out"].count("✅")
    errors = r["out"].count("❌")
    return passes, errors, f"rc={r['rc']}"


def run_julia() -> Tuple[int, int, str]:
    test = os.path.join(ROOT, "julia", "AVMIsa", "test_avm.jl")
    if not os.path.exists(test):
        return 0, 0, "test file missing"
    r = _run(["julia", test])
    # Julia TestSummary format: "|   Pass  Total  Time" / "|    12     12  0.8s"
    # Look for the numeric line after "Test Summary:"
    for line in r["out"].splitlines():
        if "|" in line:
            parts = [p.strip() for p in line.split("|")]
            for part in parts:
                nums = part.strip().split()
                if len(nums) >= 2 and nums[0].isdigit() and nums[1].isdigit():
                    return int(nums[0]), int(nums[1]) - int(nums[0]), ""
    return 0, 0, f"rc={r['rc']}"


def run_r() -> Tuple[int, int, str]:
    test = os.path.join(ROOT, "r", "AVMIsa", "test_avm.r")
    if not os.path.exists(test):
        return 0, 0, "test file missing"
    r = _run(["Rscript", test])
    passes = r["out"].count("PASS:")
    errors = r["out"].count("FAIL:")
    return passes, errors, f"rc={r['rc']}"


def run_rust() -> Tuple[int, int, str]:
    r = _run(["cargo", "test"], cwd=os.path.join(ROOT, "rust"), timeout=120)
    # Parse "test result: X passed; Y failed"
    m = re.search(r'test result:\s+(\w+)\.\s+(\d+)\s+passed;\s+(\d+)\s+failed', r["out"] + r["err"])
    if m:
        return int(m.group(2)), int(m.group(3)), ""
    # Fallback: count "ok" + "FAILED"
    p = (r["out"] + r["err"]).count("ok")
    f = (r["out"] + r["err"]).count("FAILED")
    return p, f, f"rc={r['rc']}"


def _count_pf(out: str) -> Tuple[int, int]:
    p = out.count("PASS:") + out.count("✅") + out.count("✓")
    f = out.count("FAIL:") + out.count("❌") + out.count("✗")
    return p, f


def run_c() -> Tuple[int, int, str]:
    r = _run(["sh", "-c", "cd /home/allaun/SilverSight/c && gcc -o /tmp/avm_c_test test_avm.c -lm && /tmp/avm_c_test"], timeout=30)
    p, f = _count_pf(r["out"])
    return p, f, f"rc={r['rc']}"


def run_cpp() -> Tuple[int, int, str]:
    r = _run(["sh", "-c", "cd /home/allaun/SilverSight/cpp && g++ -o /tmp/avm_cpp_test test_avm.cpp && /tmp/avm_cpp_test"], timeout=30)
    p, f = _count_pf(r["out"])
    return p, f, f"rc={r['rc']}"


def run_go() -> Tuple[int, int, str]:
    r = _run(["go", "test", "-v"], cwd=os.path.join(ROOT, "go"), timeout=60)
    p, f = _count_pf(r["out"] + r["err"])
    return p, f, f"rc={r['rc']}"


def run_fortran() -> Tuple[int, int, str]:
    r = _run(["which", "gfortran"])
    if r["rc"] != 0:
        return 0, 0, "gfortran not found"
    r = _run(["sh", "-c",
              "cd /home/allaun/SilverSight/fortran && gfortran -c avm.f90 -o /tmp/avm_f90.o && gfortran -o /tmp/avm_f90_test test_avm.f90 /tmp/avm_f90.o && /tmp/avm_f90_test"],
             timeout=30)
    p, f = _count_pf(r["out"])
    return p, f, f"rc={r['rc']}"


def run_scala() -> Tuple[int, int, str]:
    r = _run(["which", "scala-cli"])
    if r["rc"] != 0:
        return 0, 0, "scala-cli not found"
    r = _run(["scala-cli", "--power", "run", "--server=false",
              os.path.join(ROOT, "scala", "avm.scala"),
              os.path.join(ROOT, "scala", "TestAVM.scala")], timeout=60)
    p, f = _count_pf(r["out"])
    return p, f, f"rc={r['rc']}"


def run_octave() -> Tuple[int, int, str]:
    r = _run(["octave", "--no-gui", "-q", "test_avm.m"],
             cwd=os.path.join(ROOT, "octave"), timeout=30)
    p, f = _count_pf(r["out"])
    return p, f, f"rc={r['rc']}"


# ── Language registry ──────────────────────────────────────────────

LANGUAGES: Dict[str, Callable] = {
    "Python": run_python,
    "Julia": run_julia,
    "R": run_r,
    "Rust": run_rust,
    "C": run_c,
    "C++": run_cpp,
    "Go": run_go,
    "Fortran": run_fortran,
    "Scala": run_scala,
    "Octave": run_octave,
}


# ── Main ───────────────────────────────────────────────────────────

def build_panel():
    print("=" * 90)
    print("AVM Dataset Panel — Cross-Language Dispatcher")
    print("=" * 90)
    print()
    print("Running all language test harnesses...")
    print()

    results = {}
    for lang_name, runner in LANGUAGES.items():
        print(f"  [{lang_name:10s}] ", end="", flush=True)
        passes, fails, note = runner()
        results[lang_name] = (passes, fails, note)
        if fails == 0 and passes > 0:
            print(f"✅  {passes} passed")
        elif fails > 0:
            print(f"❌  {passes} passed, {fails} failed  ({note})")
        else:
            print(f"⚪  {passes} passed, {fails} failed  ({note})")

    # Summary
    print()
    print("-" * 90)
    print(f"{'Language':12s} {'Status':8s} {'Passed':8s} {'Failed':8s}  Notes")
    print("-" * 90)

    total_p, total_f = 0, 0
    all_pass = True

    for lang_name, (passes, fails, note) in results.items():
        total_p += passes
        total_f += fails
        if passes > 0 and fails == 0:
            status = "✅"
        elif fails > 0:
            status = "❌"
            all_pass = False
        elif passes == 0:
            status = "⚪"
            all_pass = False
        else:
            status = "?"
        print(f"{lang_name:12s} {status:8s} {passes:8d} {fails:8d}  {note}")

    print("-" * 90)
    verdict = "ALL CONSISTENT" if all_pass else "NOT all consistent (missing/partial coverage)"
    print(f"\nTotal: {total_p} passed, {total_f} failed across {len(LANGUAGES)} languages")
    print(f"Verdict: {verdict}")
    print()
    print("=" * 90)


if __name__ == "__main__":
    build_panel()
