from __future__ import annotations

import base64
import hashlib
import json
import platform
import re
import sys
from pathlib import Path

import qrcode
from qrcode.constants import (
    ERROR_CORRECT_H,
    ERROR_CORRECT_L,
    ERROR_CORRECT_M,
    ERROR_CORRECT_Q,
)
from qrcode.image.svg import SvgPathImage


ROOT = Path(__file__).resolve().parent
OUTPUT = ROOT / "outputs"
SOURCE = ROOT / "site.html"
ERROR_CORRECTION = {
    "L": ERROR_CORRECT_L,
    "M": ERROR_CORRECT_M,
    "Q": ERROR_CORRECT_Q,
    "H": ERROR_CORRECT_H,
}


def minify_html(source: str) -> str:
    text = re.sub(r"<!--.*?-->", "", source, flags=re.S)
    text = re.sub(r"\s+", " ", text).strip()
    text = re.sub(r">\s+<", "><", text)
    text = re.sub(r"\s*([{}:;,])\s*", r"\1", text)
    return text


def sha256(value: str) -> str:
    return hashlib.sha256(value.encode("utf-8")).hexdigest()


def build_qr(payload: str, level: str) -> dict[str, object]:
    qr = qrcode.QRCode(
        version=None,
        error_correction=ERROR_CORRECTION[level],
        box_size=10,
        border=4,
    )
    qr.add_data(payload, optimize=0)
    qr.make(fit=True)

    png_path = OUTPUT / f"website-qr-{level}.png"
    svg_path = OUTPUT / f"website-qr-{level}.svg"
    qr.make_image(fill_color="black", back_color="white").save(png_path)
    qr.make_image(image_factory=SvgPathImage).save(svg_path)

    return {
        "level": level,
        "version": qr.version,
        "modules": qr.modules_count,
        "rendered_modules_with_border": qr.modules_count + 8,
        "png": png_path.name,
        "svg": svg_path.name,
    }


def main() -> None:
    OUTPUT.mkdir(parents=True, exist_ok=True)
    source = SOURCE.read_text(encoding="utf-8")
    minified = minify_html(source)
    encoded = base64.b64encode(minified.encode("utf-8")).decode("ascii")
    payload = f"data:text/html;base64,{encoded}"

    (OUTPUT / "site.min.html").write_text(minified, encoding="utf-8")
    (OUTPUT / "payload.txt").write_text(payload, encoding="utf-8")

    manifest = {
        "format": "qr-contained-website-experiment/v1",
        "source_bytes": len(source.encode("utf-8")),
        "minified_html_bytes": len(minified.encode("utf-8")),
        "base64_bytes": len(encoded.encode("ascii")),
        "payload_bytes": len(payload.encode("ascii")),
        "payload_prefix": "data:text/html;base64,",
        "source_sha256": sha256(source),
        "minified_html_sha256": sha256(minified),
        "payload_sha256": sha256(payload),
        "python": platform.python_version(),
        "qrcode": getattr(qrcode, "__version__", "8.2"),
        "outputs": [build_qr(payload, level) for level in ERROR_CORRECTION],
    }
    (OUTPUT / "manifest.json").write_text(
        json.dumps(manifest, indent=2) + "\n", encoding="utf-8"
    )
    json.dump(manifest, sys.stdout, indent=2)
    print()


if __name__ == "__main__":
    main()
