#!/usr/bin/env python3
"""Internal synthetic graph-reference fixture. NOT a benchmark of the shipping Zortex app.

Run: python3 app/static/assets/v2/eval/run.py
Produces deterministic, auditable results.json and chart.svg next to this file.
Only Python's standard library is used. No user records, network or AI models.
"""
import json
from pathlib import Path
from xml.sax.saxutils import escape

HERE = Path(__file__).resolve().parent
N = 48
CATEGORIES = ("project", "document", "meeting", "thread")
LABELS = {
    "project": "Direct project owner",
    "document": "Document → project → owner",
    "meeting": "Meeting → project → owner",
    "thread": "Thread → project → owner",
}
SOURCE = {"project": "projects", "document": "files", "meeting": "calendar", "thread": "messages"}


def make_fixture():
    """A known owner for each project; deliberately remove some cross-app links."""
    projects = {f"p{i:02}": f"person-{i:02}" for i in range(N)}
    links = {}
    for i in range(N):
        for kind in CATEGORIES[1:]:
            missing = ((kind == "document" and i % 8 == 0)
                       or (kind == "meeting" and i % 6 == 0)
                       or (kind == "thread" and i % 4 == 0))
            if not missing:
                links[(kind, i)] = f"p{i:02}"
    return projects, links


def lookup(kind, i, projects, links, permitted):
    """Simplified reference logic: check source permission before traversing edges."""
    if SOURCE[kind] not in permitted:
        return None
    project_id = f"p{i:02}" if kind == "project" else links.get((kind, i))
    if project_id is None or "projects" not in permitted:
        return None
    return projects.get(project_id)


def chart(rows):
    # This SVG, like the other site graphics, uses only the site's white/ink/blue palette.
    parts = ['<svg xmlns="http://www.w3.org/2000/svg" role="img" '
             'aria-labelledby="title desc" viewBox="0 0 1120 515">',
             '<title id="title">Reference owner lookup results</title>',
             '<desc id="desc">Four task categories with 48 generated project cases each. '
             'Bar labels show correct owner answers and percentages.</desc>',
             '<rect width="1120" height="515" fill="#ffffff"/>',
             '<style>text{font-family:Inter,Arial,sans-serif;fill:#111111}'
             '.label{font-size:23px}.value{font-size:23px;font-weight:600}'
             '.small{font-size:18px;fill:#676767}.rule{stroke:#111111;stroke-width:1}</style>',
             '<text x="46" y="53" font-size="29" font-weight="600">Answer resolution by relationship type</text>',
             '<text class="small" x="46" y="85">Owner lookup results · 48 projects per task</text>',
             '<line class="rule" x1="46" y1="112" x2="1074" y2="112"/>']
    for j, row in enumerate(rows):
        y = 164 + j * 87
        rate = row["correct"] / row["total"]
        parts.extend([
            f'<text class="label" x="46" y="{y}">{escape(LABELS[row["type"]])}</text>',
            f'<rect x="46" y="{y + 14}" width="832" height="17" fill="#f6f6f6"/>',
            f'<rect x="46" y="{y + 14}" width="{832*rate:.2f}" height="17" fill="#005fcc"/>',
            f'<text class="value" x="902" y="{y + 27}">{row["correct"]}/{row["total"]} · {100*rate:.1f}%</text>',
        ])
    parts.extend(['<line class="rule" x1="46" y1="492" x2="1074" y2="492"/>',
                  '<text class="small" x="46" y="511">Deliberate missing links: 6 documents · 8 meetings · 12 threads</text>',
                  '</svg>'])
    original = "\n".join(parts) + "\n"
    opening = original.split(">", 1)[0] + ">"
    opening = opening.replace('viewBox="0 0 1120 515"', 'viewBox="0 0 1600 900"')
    opening = opening[:-1] + ' width="1600" height="900">'
    interior = original[len(original.split(">", 1)[0]) + 1:].removesuffix("</svg>\n")
    return (opening + '\n<rect width="1600" height="900" fill="#ffffff"/>\n'
            + '<g transform="translate(0 82.14286) scale(1.42857)">\n'
            + interior + '\n</g>\n</svg>\n')


def main():
    projects, links = make_fixture()
    cases, rows, denied = [], [], []
    all_sources = set(SOURCE.values())
    for kind in CATEGORIES:
        correct = 0
        for i in range(N):
            expected = projects[f"p{i:02}"]
            actual = lookup(kind, i, projects, links, all_sources)
            ok = actual == expected
            correct += ok
            cases.append({"type": kind, "id": f"{kind}-{i:02}", "expected": expected,
                          "returned": actual, "correct": ok})
            if kind != "project":
                permitted = all_sources - {SOURCE[kind]}
                actual_denied = lookup(kind, i, projects, links, permitted)
                denied.append({"type": kind, "id": f"{kind}-{i:02}",
                               "denied_source": SOURCE[kind], "returned": actual_denied,
                               "passes": actual_denied is None})
        rows.append({"type": kind, "correct": correct, "total": N,
                     "percent": round(100*correct/N, 1)})
    assert len(cases) == 4*N and len(denied) == 3*N
    assert all(d["passes"] for d in denied), "Permission boundary leaked a denied record"
    result = {
        "title": "Zortex V2 launch — internal synthetic reference retrieval evaluation",
        "disclaimer": "Tests only this toy reference algorithm, NOT the Zortex application, connector freshness, AI answers or production privacy.",
        "method": "48 invented projects, each with one document, meeting and thread. An owner is stored only on the project; cross-app links are withheld deterministically for selected fixture IDs. Exact-match resolution checks each required source permission before following a link. No ML model or network calls.",
        "cases_per_task": N, "task_summary": rows, "total_tasks": len(cases),
        "denied_source_checks": len(denied),
        "denied_source_exposures": sum(d["returned"] is not None for d in denied),
        "cases": cases, "denied_cases": denied,
    }
    HERE.joinpath("results.json").write_text(json.dumps(result, indent=2, sort_keys=True, ensure_ascii=False) + "\n", encoding="utf-8")
    HERE.joinpath("chart.svg").write_text(chart(rows), encoding="utf-8")
    print("Internal synthetic reference fixture (NOT product performance)")
    for row in rows:
        print(f'{row["type"]:>8}: {row["correct"]:2}/{row["total"]} = {row["percent"]:5.1f}%')
    print(f'Denied-source exposures: {result["denied_source_exposures"]}/{len(denied)}')
    print("Wrote results.json and chart.svg")


if __name__ == "__main__":
    main()
