#!/usr/bin/env python3
"""
Generic 2-test spike validator (vanilla headless vs CDP-attached Chrome).

Usage: test.py <spike-name> <button-id> [wait-ms]

Examples:
  python3 test.py apen-mouse start-real 12000
  python3 test.py css-render-chain run-all 8000
  python3 test.py lockedapart run-batch 15000
  python3 test.py phase-imaging start-collection 10000
  python3 test.py wasm-fingerprinting run-all 12000
  python3 test.py wasm-js-timing run-all 10000

For each spike, this script:
  1. Loads demo.html from local 3457 server
  2. Clicks the specified start button
  3. Waits for the body text to stabilize
  4. Captures the full results text
  5. Runs the same flow in CDP-attached Chrome
  6. Diffs the two outputs

If outputs are nearly identical → headless-vs-headful signal (valid)
If outputs diverge significantly → CDP discriminator (needs reframing)
"""
import asyncio, json, subprocess, time, os, glob, sys
from playwright.async_api import async_playwright

PORT = 9350
CHROME = "/usr/bin/google-chrome"
if not os.path.exists(CHROME):
    cands = glob.glob("/home/huxley/.cache/ms-playwright/chromium_headless_shell-*/chrome-headless-shell-linux64/chrome-headless-shell")
    if cands: CHROME = cands[0]
print(f"Using CHROME: {CHROME}")


async def run_one(p, use_cdp, url, button_id, wait_ms):
    if use_cdp:
        proc = subprocess.Popen([CHROME, "--headless=new", "--no-sandbox", "--disable-gpu",
                                  f"--remote-debugging-port={PORT}", "--user-data-dir=/tmp/gen_test_cdp",
                                  "about:blank"],
                                 stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        time.sleep(3)
        try:
            browser = await p.chromium.connect_over_cdp(f"http://localhost:{PORT}")
            ctx = browser.contexts[0] if browser.contexts else await browser.new_context()
            page = ctx.pages[0] if ctx.pages else await ctx.new_page()
        except Exception as e:
            proc.terminate()
            return {"error": f"CDP connect failed: {e}"}
    else:
        browser = await p.chromium.launch(headless=True, args=["--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage"])
        page = await (await browser.new_context()).new_page()

    try:
        await page.goto(url, wait_until="networkidle", timeout=15000)
        # Click the start button
        try:
            await page.click(f"#{button_id}", timeout=3000)
        except Exception as e:
            return {"error": f"Could not click #{button_id}: {e}"}
        # Wait for analysis to complete
        await page.wait_for_timeout(wait_ms)
        text = await page.inner_text("body")
        await browser.close()
    finally:
        if use_cdp:
            proc.terminate()
            time.sleep(1)
            if proc.poll() is None: proc.kill()
    return {"body": text}


def extract_findings(text):
    """Pull out verdict/score/flag-like lines from arbitrary text."""
    findings = []
    for line in text.split("\n"):
        line = line.strip()
        if any(k in line.lower() for k in ["verdict", "bot", "human", "score:", "detected", "suspicious", "passed", "failed", "flag"]):
            if len(line) > 5 and len(line) < 200:
                findings.append(line)
    return findings


def diff_outputs(a, b):
    """Rough text diff — return lines unique to each side."""
    set_a = set(a.split("\n"))
    set_b = set(b.split("\n"))
    only_a = [l.strip() for l in (set_a - set_b) if l.strip() and len(l.strip()) > 3]
    only_b = [l.strip() for l in (set_b - set_a) if l.strip() and len(l.strip()) > 3]
    return only_a[:30], only_b[:30]


async def main():
    if len(sys.argv) < 3:
        print(__doc__)
        sys.exit(1)
    spike = sys.argv[1]
    button_id = sys.argv[2]
    wait_ms = int(sys.argv[3]) if len(sys.argv) > 3 else 10000
    url = f"http://127.0.0.1:3457/spikes/{spike}/demo.html"

    async with async_playwright() as p:
        v = await run_one(p, False, url, button_id, wait_ms)
        c = await run_one(p, True, url, button_id, wait_ms)

    print("=" * 60)
    print(f"SPIKE: {spike}  |  BUTTON: #{button_id}  |  WAIT: {wait_ms}ms")
    print("=" * 60)
    if "error" in v or "error" in c:
        print(f"Vanilla error: {v.get('error')}")
        print(f"CDP error: {c.get('error')}")
        return
    print(f"Vanilla body length: {len(v['body'])}, CDP body length: {len(c['body'])}")
    print()
    print("--- VANILLA HEADLESS (verdict/score/flag lines) ---")
    for f in extract_findings(v["body"]):
        print(f"  {f}")
    print()
    print("--- CDP-ATTACHED (verdict/score/flag lines) ---")
    for f in extract_findings(c["body"]):
        print(f"  {f}")
    print()
    only_v, only_c = diff_outputs(v["body"], c["body"])
    print("=" * 60)
    print("VERDICT")
    print("=" * 60)
    print(f"  Lines unique to vanilla: {len(only_v)}")
    print(f"  Lines unique to CDP:     {len(only_c)}")
    if only_v or only_c:
        print(f"  Sample diff:")
        for l in (only_v + only_c)[:10]:
            print(f"    {l}")
    if len(only_v) <= 3 and len(only_c) <= 3:
        print(f"  ✅ Near-identical output. NOT a CDP discriminator.")
        print(f"     → Check demo's bot/human verdict to confirm headless-vs-headful discrimination.")
    else:
        print(f"  ⚠️  Outputs diverge — investigate the diff.")


asyncio.run(main())
