#!/usr/bin/env python3

import json
import sys
from pathlib import Path

from PyQt5.QtCore import QTimer, QUrl
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineWidgets import QWebEngineView


URL = "http://127.0.0.1:8785/agents/scanforge/"
OUTPUT = Path(sys.argv[1]).resolve()

app = QApplication.instance() or QApplication(sys.argv)

view = QWebEngineView()
view.resize(1600, 880)
view.show()

state = {
    "load_finished": False,
    "load_success": False,
    "layout": None,
    "screenshot_saved": False,
    "white_ratio": None,
}


def fail(message):
    print(f"FAIL: {message}")
    app.exit(1)


def inspect_pixels():
    pixmap = view.grab()

    if pixmap.isNull():
        fail("Could not capture the rendered ScanForge viewport.")
        return

    image = pixmap.toImage()

    if image.width() < 1400 or image.height() < 700:
        fail(
            "Captured viewport has invalid dimensions: "
            f"{image.width()}x{image.height()}"
        )
        return

    screenshot = OUTPUT / "scanforge-render.png"

    if not image.save(str(screenshot)):
        fail("Could not save the rendered screenshot.")
        return

    state["screenshot_saved"] = True

    start_y = int(image.height() * 0.75)
    sampled = 0
    nearly_white = 0

    for y in range(start_y, image.height(), 4):
        for x in range(0, image.width(), 4):
            colour = image.pixelColor(x, y)

            sampled += 1

            if (
                colour.red() >= 242
                and colour.green() >= 242
                and colour.blue() >= 242
                and colour.alpha() >= 240
            ):
                nearly_white += 1

    ratio = (
        nearly_white / sampled
        if sampled
        else 1.0
    )

    state["white_ratio"] = ratio

    print(
        "Captured viewport:",
        f"{image.width()}x{image.height()}",
    )
    print(
        "Nearly-white pixels in lower quarter:",
        f"{ratio:.6%}",
    )

    if ratio > 0.05:
        fail(
            "A large white region remains in the lower viewport."
        )
        return

    print("Rendered lower viewport: DARK")
    QTimer.singleShot(100, app.quit)


def inspect_layout(successful):
    state["load_finished"] = True
    state["load_success"] = bool(successful)

    if not successful:
        fail("ScanForge page failed to load.")
        return

    javascript = """
    (() => {
      const html = document.documentElement;
      const body = document.body;
      const root = document.getElementById('root');

      const info = element => {
        if (!element) return null;

        const rect = element.getBoundingClientRect();
        const style = getComputedStyle(element);

        return {
          width: rect.width,
          height: rect.height,
          scrollWidth: element.scrollWidth,
          scrollHeight: element.scrollHeight,
          background: style.backgroundColor,
          overflow: style.overflow,
          display: style.display
        };
      };

      return {
        readyState: document.readyState,
        innerWidth: window.innerWidth,
        innerHeight: window.innerHeight,
        devicePixelRatio: window.devicePixelRatio,
        html: info(html),
        body: info(body),
        root: info(root)
      };
    })();
    """

    def measured(value):
        state["layout"] = value
        print(json.dumps(value, indent=2))

        QTimer.singleShot(
            900,
            inspect_pixels,
        )

    view.page().runJavaScript(
        javascript,
        measured,
    )


view.loadFinished.connect(inspect_layout)
view.load(QUrl(URL))

QTimer.singleShot(
    20000,
    lambda: fail(
        "Real viewport verification timed out."
    ),
)

exit_code = app.exec_()

if exit_code != 0:
    raise SystemExit(exit_code)

if not state["load_finished"]:
    raise SystemExit(
        "FAIL: loadFinished was never received."
    )

if not state["load_success"]:
    raise SystemExit(
        "FAIL: ScanForge did not load successfully."
    )

layout = state["layout"]

if not isinstance(layout, dict):
    raise SystemExit(
        "FAIL: Browser layout data was unavailable."
    )

width = float(layout.get("innerWidth") or 0)
height = float(layout.get("innerHeight") or 0)

if width < 1400 or height < 700:
    raise SystemExit(
        "FAIL: Browser viewport remained invalid: "
        f"{width}x{height}"
    )

for name in ("html", "body", "root"):
    element = layout.get(name)

    if not isinstance(element, dict):
        raise SystemExit(
            f"FAIL: {name} layout data is missing."
        )

    element_height = float(
        element.get("height")
        or 0
    )

    if element_height < height - 3:
        raise SystemExit(
            f"FAIL: {name} height is "
            f"{element_height}px for a "
            f"{height}px viewport."
        )

    background = str(
        element.get("background")
        or ""
    ).lower()

    if background in {
        "rgb(255, 255, 255)",
        "rgba(255, 255, 255, 1)",
        "white",
    }:
        raise SystemExit(
            f"FAIL: {name} background is white."
        )

if not state["screenshot_saved"]:
    raise SystemExit(
        "FAIL: Rendered screenshot was not saved."
    )

if (
    state["white_ratio"] is None
    or state["white_ratio"] > 0.05
):
    raise SystemExit(
        "FAIL: White lower-panel check did not pass."
    )

print()
print("REAL SCANFORGE VIEWPORT: PASS")
print("Viewport dimensions: PASS")
print("Full-height HTML: PASS")
print("Full-height body: PASS")
print("Full-height React root: PASS")
print("Dark page backgrounds: PASS")
print("White lower panel: ELIMINATED")
print("Rendered screenshot:", OUTPUT / "scanforge-render.png")
