#!/usr/bin/env python3
"""Synthetic RED/GREEN proofs for ThemeFactory's release-critical runtime guards."""
from __future__ import annotations

import argparse
import json
import os
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path
from typing import Any

ROOT = Path(__file__).resolve().parents[2]
HARNESS = ROOT / "tests/runtime/runtime_harness.py"

STYLE = """/*
Theme Name: {title}
Version: 1.0.0
Requires at least: 6.8
Requires PHP: 8.1
Text Domain: {slug}
*/
{css}
"""
INDEX = """<?php get_header(); ?><main id="main"><h1><?php bloginfo('name'); ?></h1><?php if(have_posts()): while(have_posts()): the_post(); the_title('<h2>','</h2>'); the_content(); endwhile; endif; ?></main><?php get_footer(); ?>
"""
HEADER = """<!doctype html><html <?php language_attributes(); ?>><head><meta charset="<?php bloginfo('charset'); ?>"><?php wp_head(); ?></head><body <?php body_class(); ?>><?php wp_body_open(); ?><a href="#main">Skip to content</a><header><nav aria-label="Primary"><a href="<?php echo esc_url(home_url('/')); ?>">Home</a></nav></header>
"""
FOOTER = """<footer>ThemeFactory canary</footer><?php wp_footer(); ?></body></html>
"""


def clean(slugs: list[str]) -> None:
    for slug in slugs:
        shutil.rmtree(ROOT / "themes" / slug, ignore_errors=True)


def write_base(slug: str, contract: dict[str, Any], functions: str = "<?php\n", css: str = "", extra: dict[str, str] | None = None) -> Path:
    d = ROOT / "themes" / slug
    d.mkdir(parents=True, exist_ok=False)
    (d / "style.css").write_text(STYLE.format(title=f"ThemeFactory Canary {slug}", slug=slug, css=css))
    (d / "index.php").write_text(INDEX)
    (d / "header.php").write_text(HEADER)
    (d / "footer.php").write_text(FOOTER)
    (d / "functions.php").write_text(functions)
    (d / "theme-test.yaml").write_text(json.dumps(contract, indent=2) + "\n")
    for rel, body in (extra or {}).items():
        p = d / rel
        p.parent.mkdir(parents=True, exist_ok=True)
        p.write_text(body)
    return d


def base_contract(arch: str = "classic", **features: bool) -> dict[str, Any]:
    f = {
        "demo_import": False,
        "custom_blocks": False,
        "custom_post_types": False,
        "forms": False,
        "page_templates": False,
        "woocommerce": False,
    }
    f.update(features)
    return {
        "schema": 1,
        "architecture": arch,
        "workflow": "enhancement",
        "features": f,
        "runtime": {"routes": ["/"], "browser_shards": "auto"},
        "plugins": [],
        "screenshot": {"dimensions": [1200, 900]},
    }


def run_theme(slug: str, tests: list[str], out: Path, engine: str) -> tuple[int, dict[str, Any]]:
    env = os.environ.copy()
    env["THEMEFACTORY_SHARD_ID"] = "guard-" + slug
    env["THEMEFACTORY_CONTAINER_ENGINE"] = engine
    cp = subprocess.run(
        [sys.executable, str(HARNESS), "--theme", slug, "--tests", json.dumps(tests, separators=(",", ":")), "--out", str(out), "--engine", engine],
        cwd=ROOT,
        env=env,
    )
    data = json.loads(out.read_text()) if out.exists() else {}
    return cp.returncode, data


def result(data: dict[str, Any], tid: str) -> dict[str, Any] | None:
    return next((x for x in data.get("results", []) if x.get("id") == tid), None)


def assert_green(data: dict[str, Any], tids: list[str]) -> None:
    bad = [(tid, result(data, tid)) for tid in tids if not result(data, tid) or result(data, tid).get("status") != "passed"]
    if bad:
        raise RuntimeError("GREEN canary failed: " + json.dumps(bad, indent=2))


def assert_red(data: dict[str, Any], tids: list[str]) -> None:
    missed = [(tid, result(data, tid)) for tid in tids if not result(data, tid) or result(data, tid).get("status") != "failed"]
    if missed:
        raise RuntimeError("RED canary unexpectedly passed: " + json.dumps(missed, indent=2))


def proof_pair(name: str, green: dict[str, Any], red: dict[str, Any], green_ids: list[str], red_ids: list[str]) -> dict[str, Any]:
    assert_green(green, green_ids)
    assert_red(red, red_ids)
    return {
        "guard_family": name,
        "green": {tid: result(green, tid) for tid in green_ids},
        "red": {tid: result(red, tid) for tid in red_ids},
    }


def permalink_canary(work: Path, engine: str) -> dict[str, Any]:
    good, bad = "__tf-canary-rewrite-good", "__tf-canary-rewrite-bad"
    clean([good, bad])
    try:
        template = """<?php
function {p}_register() {{ if ( ! get_option('tf_canary_rewrite_enabled') ) return; register_post_type('tf_item', array('public'=>true,'has_archive'=>true,'rewrite'=>array('slug'=>'tf-items'),'label'=>'TF Items','show_in_rest'=>true)); }}
add_action('init','{p}_register');
{activation}
"""
        for slug, ok in ((good, True), (bad, False)):
            p = slug.replace("-", "_")
            if ok:
                activation = f"function {p}_activate() {{ update_option('tf_canary_rewrite_enabled','1'); {p}_register(); flush_rewrite_rules(); }}\nadd_action('after_switch_theme','{p}_activate');"
            else:
                activation = f"function {p}_activate() {{ update_option('tf_canary_rewrite_enabled','1'); }}\nadd_action('after_switch_theme','{p}_activate');"
            c = base_contract(custom_post_types=True)
            c["runtime"]["routes"] = "auto"
            write_base(slug, c, template.format(p=p, activation=activation))
        _, g = run_theme(good, ["TF-RUNTIME-001", "TF-INSTALL-001"], work / "rewrite-good.json", engine)
        _, b = run_theme(bad, ["TF-RUNTIME-001", "TF-INSTALL-001"], work / "rewrite-bad.json", engine)
        return proof_pair("permalink-lifecycle", g, b, ["TF-INSTALL-001"], ["TF-INSTALL-001"])
    finally:
        clean([good, bad])


def editor_canary(work: Path, engine: str) -> dict[str, Any]:
    good, bad = "__tf-canary-editor-good", "__tf-canary-editor-bad"
    clean([good, bad])
    try:
        good_fn = "<?php\n"
        bad_fn = r'''<?php
function tf_bad_editor_assets(){ wp_add_inline_script('wp-blocks', 'console.error("TF_EDITOR_CANARY_BROKEN");'); }
add_action('enqueue_block_editor_assets','tf_bad_editor_assets',99);
function tf_bad_strip_sentinel($data,$postarr){ if(($data['post_type']??'')==='page' && strpos($data['post_content']??'','TF_EDIT_')!==false){ $data['post_content']=preg_replace('/<!-- wp:paragraph.*?TF_EDIT_.*?<!-- \/wp:paragraph -->/s','',$data['post_content']); } return $data; }
add_filter('wp_insert_post_data','tf_bad_strip_sentinel',99,2);
'''
        c = base_contract("gutenberg-hybrid")
        write_base(good, c, good_fn)
        write_base(bad, c, bad_fn)
        ids = ["TF-EDITOR-001", "TF-EDITABILITY-001"]
        _, g = run_theme(good, ids, work / "editor-good.json", engine)
        _, b = run_theme(bad, ids, work / "editor-bad.json", engine)
        return proof_pair("editor-editability", g, b, ids, ids)
    finally:
        clean([good, bad])


def importer_functions(prefix: str, good: bool) -> str:
    menu = (
        f"add_theme_page('Import Demo','Import Demo','manage_options','{prefix}-import','{prefix}_page');"
        if good
        else f"add_menu_page('Import Demo','Import Demo','manage_options','{prefix}-import','{prefix}_page');"
    )
    notice = (
        f"function {prefix}_notice(){{ if(get_option('{prefix}_notice')) echo '<div class=\"notice notice-info\"><p>Import demo content <a href=\"'.esc_url(admin_url('themes.php?page={prefix}-import')).'\">Import Demo</a></p></div>'; }} add_action('admin_notices','{prefix}_notice');"
        if good
        else ""
    )
    create = (
        f"$p=get_page_by_path('tf-demo-content'); if(!$p) wp_insert_post(array('post_type'=>'page','post_status'=>'publish','post_title'=>'TF Demo Content','post_name'=>'tf-demo-content'));"
        if good
        else "wp_insert_post(array('post_type'=>'page','post_status'=>'publish','post_title'=>'TF Demo Duplicate','post_name'=>'tf-demo-'.wp_generate_uuid4()));"
    )
    return f'''<?php
function {prefix}_activate(){{ update_option('{prefix}_notice','1'); }} add_action('after_switch_theme','{prefix}_activate');
function {prefix}_menu(){{ {menu} }} add_action('admin_menu','{prefix}_menu');
function {prefix}_page(){{ echo '<div class="wrap"><h1>Import Demo</h1><form method="post" action="'.esc_url(admin_url('admin-post.php')).'"><input type="hidden" name="action" value="{prefix}_import_action">'; wp_nonce_field('{prefix}_import','{prefix}_nonce'); submit_button('Import Demo'); echo '</form></div>'; }}
function {prefix}_import(){{ if(!current_user_can('manage_options')) wp_die('forbidden'); check_admin_referer('{prefix}_import','{prefix}_nonce'); {create} update_option('{prefix}_notice','0'); wp_safe_redirect(admin_url('{('themes.php?page='+prefix+'-import') if good else ('admin.php?page='+prefix+'-import')}&done=1')); exit; }} add_action('admin_post_{prefix}_import_action','{prefix}_import');
{notice}
'''


def demo_canary(work: Path, engine: str) -> dict[str, Any]:
    good, bad = "__tf-canary-demo-good", "__tf-canary-demo-bad"
    clean([good, bad])
    try:
        for slug, ok in ((good, True), (bad, False)):
            prefix = slug.replace("-", "_")
            c = base_contract(demo_import=True)
            c["demo_import"] = {
                "location": "appearance",
                "activation_notice": True,
                "idempotent": True,
                "admin_path": (f"themes.php?page={prefix}-import" if ok else f"admin.php?page={prefix}-import"),
                "completion_text": "Import Demo",
            }
            write_base(slug, c, importer_functions(prefix, ok))
        good_ids = ["TF-DEMO-001", "TF-DEMO-002", "TF-DEMO-003", "TF-DEMO-004", "TF-DEMO-005"]
        bad_ids = ["TF-DEMO-001", "TF-DEMO-002", "TF-DEMO-004"]
        _, g = run_theme(good, good_ids, work / "demo-good.json", engine)
        _, b = run_theme(bad, bad_ids, work / "demo-bad.json", engine)
        return proof_pair("demo-import", g, b, good_ids, bad_ids)
    finally:
        clean([good, bad])


def layout_template_functions(prefix: str, good: bool) -> str:
    meta = "update_post_meta($id,'_wp_page_template','page-templates/canary.php');" if good else ""
    content = "<!-- wp:paragraph --><p>Editable canary body</p><!-- /wp:paragraph -->" if good else "<div>Classic-only body</div>"
    pattern = (
        f"function {prefix}_pattern(){{ if(function_exists('register_block_pattern')) register_block_pattern('{prefix}/canary',array('title'=>'Canary page','content'=>'<!-- wp:paragraph --><p>Editable canary body</p><!-- /wp:paragraph -->')); }} add_action('init','{prefix}_pattern');"
        if good
        else ""
    )
    return f'''<?php
function {prefix}_assets(){{ wp_enqueue_style('{prefix}-style',get_stylesheet_uri(),array(),null); }} add_action('wp_enqueue_scripts','{prefix}_assets');
function {prefix}_activate(){{ $p=get_page_by_path('canary'); if(!$p){{$id=wp_insert_post(array('post_type'=>'page','post_status'=>'publish','post_title'=>'Canary','post_name'=>'canary','post_content'=>{json.dumps(content)}));}}else{{$id=$p->ID;}} {meta} update_option('show_on_front','page'); update_option('page_on_front',$id); }} add_action('after_switch_theme','{prefix}_activate');
{pattern}
'''


def layout_template_canary(work: Path, engine: str) -> dict[str, Any]:
    good, bad = "__tf-canary-layout-good", "__tf-canary-layout-bad"
    clean([good, bad])
    try:
        good_css = ".tf-cards{display:flex;align-items:stretch;gap:12px}.tf-card{flex:1;border:1px solid #333;padding:8px}"
        bad_css = ".tf-cards{display:flex;align-items:flex-start;gap:12px}.tf-card{border:1px solid #333;padding:8px}"
        front = """<?php get_header(); ?><main id="main"><h1>Card canary</h1><div class="tf-cards"><article class="tf-card"><h2>Short</h2><p>One line.</p></article><article class="tf-card"><h2>Much longer title for deterministic content stress</h2><p>This card deliberately contains several more lines of content so an unstretched card has a measurably different rectangle height.</p></article></div><?php while(have_posts()):the_post();the_content();endwhile; ?></main><?php get_footer(); ?>"""
        template = """<?php /* Template Name: Canary Editable Page */ get_header(); ?><main id="main"><?php while(have_posts()):the_post();the_title('<h1>','</h1>');the_content();endwhile; ?></main><?php get_footer(); ?>"""
        for slug, ok in ((good, True), (bad, False)):
            prefix = slug.replace("-", "_")
            c = base_contract("gutenberg-hybrid", page_templates=True)
            c["runtime"]["routes"] = ["/"]
            c["components"] = {"canary_cards": {"selector": ".tf-card", "equal_height": True, "tolerance_px": 2}}
            c["pages"] = {"canary": {"path": "/canary/", "template": "page-templates/canary.php", "expected_blocks": ["core/paragraph"]}}
            extra = {"front-page.php": front}
            if ok:
                extra["page-templates/canary.php"] = template
            write_base(slug, c, layout_template_functions(prefix, ok), good_css if ok else bad_css, extra)
        ids = ["TF-UI-016", "TF-TEMPLATE-001", "TF-TEMPLATE-002", "TF-TEMPLATE-003"]
        _, g = run_theme(good, ids, work / "layout-good.json", engine)
        _, b = run_theme(bad, ids, work / "layout-bad.json", engine)
        return proof_pair("layout-templates", g, b, ids, ids)
    finally:
        clean([good, bad])


def main() -> int:
    ap = argparse.ArgumentParser()
    ap.add_argument("--family", choices=["all", "permalink", "editor", "demo", "layout"], default="all")
    args = ap.parse_args()
    engine = os.environ.get("THEMEFACTORY_CONTAINER_ENGINE", "docker")
    work = Path(tempfile.mkdtemp(prefix="tf-guard-selftest-"))
    target_dir = ROOT / ".theme-ci"
    target_dir.mkdir(exist_ok=True)
    proofs: list[dict[str, Any]] = []
    try:
        families = {
            "permalink": permalink_canary,
            "editor": editor_canary,
            "demo": demo_canary,
            "layout": layout_template_canary,
        }
        selected = list(families) if args.family == "all" else [args.family]
        for name in selected:
            proof = families[name](work, engine)
            proofs.append(proof)
            (target_dir / f"guard-selftest-{name}.json").write_text(json.dumps({"schema": 1, **proof}, indent=2) + "\n")
        aggregate = {"schema": 1, "families": proofs}
        (target_dir / "guard-selftests.json").write_text(json.dumps(aggregate, indent=2) + "\n")
        print(json.dumps(aggregate, indent=2))
        return 0
    except Exception as exc:
        print(f"guard-selftest: {type(exc).__name__}: {exc}", file=sys.stderr)
        return 1
    finally:
        # Canary themes must never survive the verifier run.
        for p in list((ROOT / "themes").glob("__tf-canary-*")):
            shutil.rmtree(p, ignore_errors=True)
        shutil.rmtree(work, ignore_errors=True)


if __name__ == "__main__":
    raise SystemExit(main())
