#!/usr/bin/env python3
"""verify-svg-xml.py — the SVG that must parse (the 08:59 catch's own seed).

The thirty-first coda's literal <desc> made the ring SVG's XML malformed
(mismatched tag at line 91 — the image would not render) while every wall
passed, caught only by a manual ElementTree parse. The wall on the image
gate verified the pages' words; the desc wall verified the files' words;
NOTHING verified the files themselves parse as XML. A tag-like word in any
desc or text node is a ghost in the drawing itself — the same class one
surface further in.

This wall is the reverse gate (declared ⊆ found) on the whole site: EVERY
*.svg the garden serves must be READ as well-formed XML by the machinery's
own parser (xml.etree.ElementTree, the same parser the 08:59 catch used by
hand). A file the wall cannot parse fails the build, named by file. The
wall reads the SVGs it can see, and the reading of WHICH SVGs exist is now
the wall's too — the finder enumerates the surface, the parser proves each
member, and a directory that vanishes the surface entirely (zero SVGs) is
a failed reading, not a green pass.

Deterministic: same files, same bytes, same verdict. Exit 1 on any file
that is not well-formed XML, or when the surface is empty.

Usage:
  python3 verify-svg-xml.py              # check every SVG under site/
Wired into verify-descs.py (imported in-process) so the finish-script gate
carries it without a new file in the wake's tail.
"""

import sys
from pathlib import Path
import xml.etree.ElementTree as ET

SITE = Path(__file__).resolve().parent.parent
MIN_FILES = 1  # the wall is never idle: an empty surface is a failed reading


def check_all():
    """Return (failed_count, lines). Verifies every *.svg under SITE parses
    as well-formed XML, named by relative path on failure."""
    lines = []
    svgs = sorted(SITE.rglob("*.svg"))
    lines.append(f"svg xml: {len(svgs)} SVG file(s) under site/")

    if len(svgs) < MIN_FILES:
        lines.append(f"  FAIL: the wall found no SVGs to read — empty surface is not a green pass")
        return 1, lines

    failed = 0
    for p in svgs:
        rel = p.relative_to(SITE)
        try:
            data = p.read_bytes()
            ET.fromstring(data)
            # NOTE: ElementTree's expat parser is the same one the 08:59
            # catch used by hand. It requires the file to be well-formed
            # XML — mismatched tags, unclosed elements, and stray markup
            # in text nodes all raise ParseError here. Comments are words,
            # not markup: a tag-like word inside an XML comment parses
            # (expat is comment-aware by construction — proven both ways
            # in verify-svg-xml-both-ways.py, cases 5/6: a '<desc>' spoken
            # about the markup stays words; a comment the file cannot
            # close is a ghost in the drawing itself and fails, named by
            # file).
        except ET.ParseError as e:
            failed += 1
            lines.append(f"  FAIL {rel}: NOT well-formed XML — {e}")
        except OSError as e:
            failed += 1
            lines.append(f"  FAIL {rel}: unreadable — {e}")
        except Exception as e:
            failed += 1
            lines.append(f"  FAIL {rel}: {type(e).__name__}: {e}")

    lines.append(f"svg xml: {len(svgs) - failed}/{len(svgs)} SVG file(s) parse as well-formed XML"
                 + ("" if failed == 0 else " — the rest are ghosts in the drawing itself"))
    return failed, lines


def main():
    failed, lines = check_all()
    for line in lines:
        print(line)
    if failed:
        print("svg-xml failed: a drawing the wall cannot parse is a ghost in the drawing itself")
        return 1
    print("svg-xml OK: every SVG the garden serves parses as well-formed XML; a tag-like word in any desc or text node fails the build, named by file.")
    return 0


if __name__ == "__main__":
    sys.exit(main())
