#!/usr/bin/env python3
import hashlib
import json
import re
import sys
import unicodedata
from datetime import datetime, timezone
from pathlib import Path

PROJECT = Path(__file__).resolve().parents[1]
PROJECTS = PROJECT.parent
CANON = PROJECT / "story/story-canon.txt"
BRIEF = PROJECT / "script/story-brief.json"
RECEIPT = PROJECT / "story/originality-report.json"
TOKEN_RE = re.compile(r"[^\W_]+", re.UNICODE)


def sha(path):
    return hashlib.sha256(path.read_bytes()).hexdigest()


def tokens(text):
    return TOKEN_RE.findall(unicodedata.normalize("NFC", text).casefold())


def shingles(items, width=10):
    return {" ".join(items[index:index + width]) for index in range(max(0, len(items) - width + 1))}


def main():
    if not CANON.is_file() or not BRIEF.is_file():
        raise RuntimeError("canon/brief missing")
    brief = json.loads(BRIEF.read_text(encoding="utf-8"))
    family_ok = bool(
        brief.get("primary_story_family") == "Thiên kim thật–giả / gia đình phản diện / trở về"
        and brief.get("secondary_story_family") == "Cưới trước yêu sau"
        and brief.get("family_engine_lock", {}).get("primary")
        and brief.get("family_engine_lock", {}).get("secondary")
    )
    current = shingles(tokens(CANON.read_text(encoding="utf-8")))
    comparisons = []
    worst = 0.0
    for directory in sorted(PROJECTS.iterdir()):
        if directory == PROJECT or not directory.is_dir() or not re.match(r"^\d{3}-", directory.name):
            continue
        other = next((path for path in (directory / "story/story-canon.txt", directory / "story/spoken-narration.txt") if path.is_file()), None)
        if other is None:
            continue
        other_set = shingles(tokens(other.read_text(encoding="utf-8")))
        overlap = len(current & other_set)
        ratio = overlap / max(1, len(current))
        worst = max(worst, ratio)
        comparisons.append({"project": directory.name, "path": str(other), "overlap_10grams": overlap, "current_overlap_ratio": ratio})
    axes = {
        "setting": bool(brief.get("setting")),
        "premise": bool(brief.get("premise")),
        "story_engine": bool(brief.get("story_engine")),
        "motifs": bool(brief.get("motifs")),
        "climax": bool(brief.get("climax")),
        "ending": bool(brief.get("ending")),
        "family_adherence": family_ok,
    }
    verified = all(axes.values()) and worst < 0.002
    receipt = {
        "version": 1,
        "verified": verified,
        "status": "passed" if verified else "failed",
        "source_canon_sha256": sha(CANON),
        "method": "normalized Unicode 10-word shingle comparison; originality inside locked story-family framework",
        "threshold": 0.002,
        "worst_current_overlap_ratio": worst,
        "authority_axes": axes,
        "primary_story_family_preserved": family_ok,
        "comparisons": comparisons,
        "checked_at": datetime.now(timezone.utc).isoformat(),
    }
    RECEIPT.write_text(json.dumps(receipt, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
    print(json.dumps({"verified": verified, "comparisons": len(comparisons), "worst_ratio": worst, "family_preserved": family_ok}, ensure_ascii=False))
    return 0 if verified else 1


if __name__ == "__main__":
    try:
        sys.exit(main())
    except Exception as exc:
        print(f"Originality gate blocked: {exc}", file=sys.stderr)
        sys.exit(1)
