#!/usr/bin/env python3
"""Generate five original subtitle fixtures and measure exact decoding results.

Run: python3 reproduce.py NEW_DIRECTORY
The directory must not exist. This is a two-cue teaching experiment, not a
subtitle player, movie, customer, OCR, or translation-product test.
Copyright 2026 BookTranslator. SPDX-License-Identifier: MIT
"""

import argparse
from datetime import datetime, timezone
import hashlib
import json
from pathlib import Path
import platform
import re


SOURCE = (
    "1\n00:00:01,000 --> 00:00:04,000\n"
    "Émile dit : « Le prix est de 12,50 €. »\n\n"
    "2\n00:00:05,000 --> 00:00:08,000\n"
    "Le café est fermé.\n\n"
)


def timestamps(text):
    return re.findall(r"^\d{2}:\d{2}:\d{2},\d{3} --> \d{2}:\d{2}:\d{2},\d{3}$", text, re.M)


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("output_directory", type=Path)
    args = parser.parse_args()
    args.output_directory.mkdir(parents=False, exist_ok=False)

    source_bytes = SOURCE.encode("utf-8")
    legacy_bytes = SOURCE.encode("cp1252")
    mojibake_text = source_bytes.decode("cp1252", errors="strict")
    loss_text = legacy_bytes.decode("utf-8", errors="replace")
    cases = [
        ("source-utf8.srt", source_bytes, "utf-8", "Original self-authored teaching text."),
        ("source-windows1252.srt", legacy_bytes, "cp1252", "Same source encoded as Windows-1252."),
        ("wrong-decoder-resaved-utf8.srt", mojibake_text.encode("utf-8"), "utf-8", "UTF-8 bytes misread as cp1252, then saved as UTF-8."),
        ("replacement-resaved-utf8.srt", loss_text.encode("utf-8"), "utf-8", "cp1252 bytes misread as UTF-8 with replacement, then saved as UTF-8."),
        ("correctly-converted-utf8.srt", legacy_bytes.decode("cp1252").encode("utf-8"), "utf-8", "Correct explicit cp1252-to-UTF8 conversion."),
    ]
    records = []
    for filename, data, intended_encoding, purpose in cases:
        with (args.output_directory / filename).open("xb") as output:
            output.write(data)
        try:
            utf8_text = data.decode("utf-8", errors="strict")
            valid_utf8 = True
        except UnicodeDecodeError:
            utf8_text = None
            valid_utf8 = False
        decoded = data.decode(intended_encoding, errors="strict")
        records.append({
            "file": filename,
            "purpose": purpose,
            "bytes": len(data),
            "sha256": hashlib.sha256(data).hexdigest(),
            "strict_utf8": valid_utf8,
            "utf8_text_equals_source": utf8_text == SOURCE if valid_utf8 else None,
            "utf8_persisted_replacement_characters": utf8_text.count("\ufffd") if valid_utf8 else None,
            "declared_decode_encoding": intended_encoding,
            "declared_decode_equals_source": decoded == SOURCE,
            "decoded_text": decoded,
            "timestamps": timestamps(decoded),
            "timestamps_equal_source": timestamps(decoded) == timestamps(SOURCE),
        })

    checks = {
        "correct_conversion_equals_original_bytes": cases[4][1] == source_bytes,
        "known_lossless_mojibake_chain_reversed": mojibake_text.encode("cp1252", errors="strict").decode("utf-8", errors="strict") == SOURCE,
        "mojibake_utf8_is_valid_but_text_is_wrong": records[2]["strict_utf8"] and not records[2]["utf8_text_equals_source"],
        "loss_fixture_has_six_persisted_replacements": records[3]["utf8_persisted_replacement_characters"] == 6,
        "all_timestamp_strings_unchanged": all(record["timestamps_equal_source"] for record in records),
        "cp1252_80_is_euro": b"\x80".decode("cp1252") == "€",
        "latin1_80_is_control_not_euro": ord(b"\x80".decode("latin-1")) == 0x80,
    }
    if not all(checks.values()):
        raise RuntimeError("An experiment check failed; do not report these results as passing.")
    result = {
        "generated_at": datetime.now(timezone.utc).isoformat(),
        "python_version": platform.python_version(),
        "platform": platform.system(),
        "corpus": "Entirely self-authored French teaching text; two cues, one known ground truth, five byte representations. No film, customer or translation output.",
        "method": "Python standard library strict UTF-8/cp1252 decoding except deliberate errors=replace in the labeled loss fixture. No autodetection, no model calls, one deterministic pass, no retries or excluded samples.",
        "review": "Exact string, byte and timestamp equality assertions; no language-quality scores or playback reviewer.",
        "limitations": "No GUI, player, fonts, platform BOM compatibility, real-media sync or BookTranslator execution tested. Exact conversion equality is not an accuracy estimate for arbitrary subtitle files.",
        "records": records,
        "checks": checks,
    }
    with (args.output_directory / "results.json").open("x", encoding="utf-8") as output:
        json.dump(result, output, ensure_ascii=False, indent=2)
        output.write("\n")
    print(json.dumps({"output_directory": str(args.output_directory), "checks": checks}, indent=2))


if __name__ == "__main__":
    main()
