#!/usr/bin/env python3
"""Static guard for the Recipe Verification visual-host layout contract.

This validator does not claim pixel-level proof. It verifies that every runtime host
uses the official scroll-safe MASApplicationWindow.Pages route, DPI-aware WinForms
hosting, minimum window bounds, and dedicated routes/height budgets for heavyweight
surfaces instead of the former single compressed LayoutPage startup.
"""
from __future__ import annotations

import argparse
import json
import re
from pathlib import Path

EXPECTED_ROUTES = {1: 4, 2: 6, 3: 4, 4: 8, 5: 1}
EXPECTED_MINIMUMS = {
    1: "1024, 700",
    2: "1080, 720",
    3: "1120, 760",
    4: "1120, 760",
    5: "1180, 780",
}


def balanced(text: str, start_pattern: str, end_pattern: str) -> bool:
    return len(re.findall(start_pattern, text, flags=re.I | re.M)) == len(
        re.findall(end_pattern, text, flags=re.I | re.M)
    )


def constructor_blocks(text: str) -> list[str]:
    return re.findall(
        r"Public\s+Sub\s+New\s*\([^)]*\)(.*?)(?:\n\s*End\s+Sub)",
        text,
        flags=re.I | re.S,
    )


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--root", default=str(Path(__file__).resolve().parents[2]))
    parser.add_argument("--write", action="store_true")
    args = parser.parse_args()
    root = Path(args.root).resolve()

    failures: list[str] = []
    results: list[dict] = []
    total_routes = 0

    for batch in range(1, 6):
        source = root / f"samples/RecipeVerification.Batch{batch}/MainForm.vb"
        batch_failures: list[str] = []
        if not source.is_file():
            batch_failures.append("MainForm.vb is missing")
            text = ""
        else:
            text = source.read_text(encoding="utf-8-sig")

        route_ids = re.findall(r"\bpages\.RegisterPage\s*\(\s*(?:pageId\s*:=\s*)?\"([^\"]+)\"", text, flags=re.I | re.S)
        route_count = len(route_ids)
        total_routes += route_count
        if route_count != EXPECTED_ROUTES[batch]:
            batch_failures.append(
                f"expected {EXPECTED_ROUTES[batch]} PageHost routes, found {route_count}"
            )

        route_array_match = re.search(
            r"RuntimeRouteIds\s+As\s+String\(\)\s*=\s*New\s+String\(\)\s*\{([^}]*)\}",
            text,
            flags=re.I | re.S,
        )
        smoke_route_ids = re.findall(r'\"([^\"]+)\"', route_array_match.group(1)) if route_array_match else []
        if route_ids != smoke_route_ids:
            batch_failures.append(
                "runtime smoke route list does not exactly match registered PageHost routes"
            )

        required_fragments = [
            "Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi",
            "Me.DoubleBuffered = True",
            "StartPosition = FormStartPosition.CenterScreen",
            "MASApplicationPageHost",
            "HandleSmokeTick",
            "_window.Pages.NavigateTo(RuntimeRouteIds(_smokeRouteIndex))",
            ".ClearPages()",
            ".RegisterPage(",
            ".Show()",
            f"New System.Drawing.Size({EXPECTED_MINIMUMS[batch]})",
        ]
        for fragment in required_fragments:
            if fragment not in text:
                batch_failures.append(f"missing visual-host contract: {fragment}")

        ctors = constructor_blocks(text)
        if not ctors:
            batch_failures.append("runtime form constructor could not be located")
        else:
            runtime_ctors = [ctor for ctor in ctors if "ConfigureRuntime" in ctor]
            if not runtime_ctors:
                batch_failures.append("runtime constructor does not activate the hardened page configuration")
            if any(re.search(r"BuildBatch\d+LandingPage", ctor, flags=re.I) for ctor in ctors):
                batch_failures.append("a runtime constructor still loads the legacy compressed landing page")

        if not balanced(text, r"^\s*(?:Public|Private|Protected|Friend)\s+(?:NotInheritable\s+)?Class\b", r"^\s*End\s+Class\b"):
            batch_failures.append("Class/End Class count is not balanced")

        if batch == 2:
            if "MASSize.FillWidth.OffsetHeight(300.0F)" not in text:
                batch_failures.append("Batch 2 DataGrid does not have a dedicated height budget")
        elif batch == 3:
            if "MASLocalizationRtl.AttachPage(_window, page)" not in text:
                batch_failures.append("Batch 3 does not use the PageHost Localization overload")
            if "MASSize.FillWidth.OffsetHeight(420.0F)" not in text:
                batch_failures.append("Batch 3 large DataGrid does not have a dedicated height budget")
            if "page.Flow()" not in text:
                batch_failures.append("Batch 3 command rows do not use wrapping Flow layout")
        elif batch == 4:
            if "ConfigureRuntimePages(window)" not in text:
                batch_failures.append("Batch 4 legacy landing entry is not redirected to PageHost")
            offset_count = len(re.findall(r"BindProductPage\([^\n]+,\s*\d+\.0F\)", text))
            if offset_count != 8:
                batch_failures.append(f"expected 8 dedicated product-control height budgets, found {offset_count}")
        elif batch == 5:
            if "MASRenderVerification.AttachDashboard(window, page)" not in text:
                batch_failures.append("Batch 5 does not use the PageHost dashboard overload")
            if "WithRhythm(MASApplicationSurfaceRhythm.Comfortable)" not in text:
                batch_failures.append("Batch 5 does not use comfortable dashboard rhythm")

        failures.extend(f"Batch {batch}: {item}" for item in batch_failures)
        results.append(
            {
                "batch": batch,
                "routes": route_count,
                "expectedRoutes": EXPECTED_ROUTES[batch],
                "status": "PASS" if not batch_failures else "FAIL",
                "failures": batch_failures,
            }
        )

    report = {
        "schema": "nexamas-ui-recipe-visual-hardening/v1",
        "status": "PASS" if not failures else "FAIL",
        "batches": 5,
        "runtimePages": total_routes,
        "scrollSafePageHosts": sum(1 for result in results if result["status"] == "PASS"),
        "pixelProof": "WINDOWS_VISUAL_RECHECK_REQUIRED",
        "results": results,
        "failures": failures,
    }

    if args.write:
        output = root / "docs/_inventory/recipe-verification-visual-hardening.json"
        output.write_text(json.dumps(report, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")

    print(json.dumps(report, indent=2, ensure_ascii=False))
    return 0 if not failures else 1


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