#!/usr/bin/env python3
"""ISBN-13 syntax/checksum examples, not an ISBN assignment lookup.

Python 3.9+; standard library only. Run without arguments for the recorded
examples, or use --isbn '978-4-10-101001-4' for one input. Only ASCII spaces
and hyphens are removed. Prefix 978/979 is required, but allocation ranges,
hyphen boundaries, catalogue metadata and physical books are not validated.
"""

import argparse
import json
import platform
import re
from datetime import datetime
from zoneinfo import ZoneInfo


def check_isbn13(raw):
    digits = raw.replace(" ", "").replace("-", "")
    result = {
        "input": raw,
        "normalized": digits,
        "syntax_ok": False,
        "checksum_ok": None,
        "assignment_checked": False,
    }
    if re.fullmatch(r"(?:978|979)[0-9]{10}", digits) is None:
        result["error"] = "expected 13 ASCII digits starting with 978 or 979"
        return result
    weighted_sum = sum(int(d) * (1 if i % 2 == 0 else 3)
                       for i, d in enumerate(digits[:12]))
    expected = (-weighted_sum) % 10
    supplied = int(digits[-1])
    result.update({
        "syntax_ok": True,
        "weighted_sum_12": weighted_sum,
        "expected_check_digit": expected,
        "supplied_check_digit": supplied,
        "checksum_ok": supplied == expected,
    })
    return result


def demo():
    original = "9784101010014"
    swapped = list(original)
    swapped[3], swapped[7] = swapped[7], swapped[3]
    swapped = "".join(swapped)
    specifications = [
        ("shinchosha_publisher_record", "978-4-10-101001-4", True, True),
        ("kadokawa_publisher_record", "9784041001011", True, True),
        ("changed_check_digit", "9784101010015", True, False),
        ("synthetic_same_weight_swap", swapped, True, True),
        ("fullwidth_digits", "９７８４１０１０１００１４", False, None),
        ("too_short", "978410101001", False, None),
        ("empty_input", "", False, None),
        ("isbn10_out_of_scope", "4101010013", False, None),
        ("letter_in_number", "97841010100A4", False, None),
    ]
    cases = []
    for label, value, expected_syntax, expected_checksum in specifications:
        result = check_isbn13(value)
        result["case"] = label
        matches = (result["syntax_ok"] == expected_syntax
                   and result["checksum_ok"] == expected_checksum)
        result["matches_expected"] = matches
        if not matches:
            raise RuntimeError("unexpected result for " + label)
        cases.append(result)
    return {
        "run_date_beijing": datetime.now(ZoneInfo("Asia/Shanghai")).date().isoformat(),
        "environment": {
            "python": platform.python_version(),
            "system": platform.system(),
            "macos": platform.mac_ver()[0],
            "machine": platform.machine(),
            "dependencies": "Python standard library only",
        },
        "scope": "syntax and ISBN-13 checksum only; no assignment or book verification",
        "synthetic_case_note": "positions 4 and 8 are swapped; no catalogue claim is made",
        "publisher_records": [
            {
                "title": "吾輩は猫である",
                "author": "夏目漱石",
                "imprint": "新潮文庫",
                "format": "paperback (bunko)",
                "pages": 624,
                "isbn13": original,
                "source": "https://www.shinchosha.co.jp/book/101001/",
                "checked_on": "2026-10-06",
                "method": "manually transcribed from the publisher page; no copy inspected",
            },
            {
                "title": "吾輩は猫である",
                "author": "夏目漱石",
                "imprint": "角川文庫",
                "format": "paperback (bunko)",
                "pages": 592,
                "isbn13": "9784041001011",
                "source": "https://www.kadokawa.co.jp/product/199999100101/",
                "checked_on": "2026-10-06",
                "method": "manually transcribed from the publisher page; no copy inspected",
            },
        ],
        "cases": cases,
        "cases_matching_expectations": len(cases),
    }


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--isbn", help="check one ISBN-13; omit to run the examples")
    args = parser.parse_args()
    result = demo() if args.isbn is None else check_isbn13(args.isbn)
    print(json.dumps(result, ensure_ascii=False, indent=2))
    if args.isbn is not None:
        if not result["syntax_ok"]:
            return 2
        return 0 if result["checksum_ok"] else 1
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
