#!/usr/bin/env python3
"""Create self-authored Japanese OCR fixtures; no book scans or OCR calls.

Usage: python generate-samples.py /path/to/NotoSansCJKjp-Regular.otf
Requires Pillow 12.3.0. Files are written beside this script.
"""

import hashlib
import json
from pathlib import Path
import sys

from PIL import Image, ImageDraw, ImageFont, __version__ as pillow_version


DESTINATION = Path(__file__).resolve().parent
FONT = Path(sys.argv[1]).resolve()
BODY = ["朝の図書館で本を読む。", "古い地図には川が見える。", "明日は友人と駅で会う。"]
RUBY = [
    {"column": 0, "start": 2, "base": "図書館", "reading": "としょかん"},
    {"column": 1, "start": 2, "base": "地図", "reading": "ちず"},
    {"column": 2, "start": 3, "base": "友人", "reading": "ゆうじん"},
    {"column": 2, "start": 6, "base": "駅", "reading": "えき"},
]
BASE_SIZE = 64
STEP = 80
RUBY_SIZE = 24
TOP = 90
COLUMN_X = [970, 570, 170]
font = ImageFont.truetype(str(FONT), BASE_SIZE)
ruby_font = ImageFont.truetype(str(FONT), RUBY_SIZE)


def character(draw, char, x, y, face, vertical=False):
    # Place the Japanese full stop at the upper-right of its vertical cell.
    # The fixture deliberately avoids brackets, Latin runs and advanced typesetting.
    if vertical and char == "。":
        draw.ellipse((x + 49, y + 2, x + 61, y + 14), outline="black", width=3)
        return
    draw.text((x, y), char, fill="black", font=face, anchor="lt")


def vertical(with_ruby):
    image = Image.new("RGB", (1200, 1260), "white")
    draw = ImageDraw.Draw(image)
    for column, line in enumerate(BODY):
        for index, char in enumerate(line):
            character(draw, char, COLUMN_X[column], TOP + STEP * index, font, True)
    if with_ruby:
        for ruby in RUBY:
            start = TOP + STEP * ruby["start"]
            available_height = len(ruby["base"]) * STEP
            ruby_step = min(40, available_height / len(ruby["reading"]))
            for index, char in enumerate(ruby["reading"]):
                character(draw, char, COLUMN_X[ruby["column"]] + 77, start + index * ruby_step, ruby_font)
    return image


horizontal = Image.new("RGB", (1200, 600), "white")
draw = ImageDraw.Draw(horizontal)
for index, line in enumerate(BODY):
    draw.text((90, 90 + index * 150), line, fill="black", font=font, anchor="lt")
images = {
    "horizontal.png": horizontal,
    "vertical.png": vertical(False),
    "vertical-furigana.png": vertical(True),
}
for column, x in enumerate(COLUMN_X):
    # A documented manual body-column crop excludes the separate ruby strip.
    # Never apply these synthetic-image coordinates to an unknown real scan.
    cropped = images["vertical-furigana.png"].crop((x - 10, TOP - 15, x + 70, 1160))
    padded = Image.new("RGB", (cropped.width + 40, cropped.height + 40), "white")
    padded.paste(cropped, (20, 20))
    images[f"body-column-{column + 1}.png"] = padded

for filename, image in images.items():
    image.save(DESTINATION / filename, dpi=(300, 300))

(DESTINATION / "ground-truth.txt").write_text("\n".join(BODY) + "\n", encoding="utf-8")
(DESTINATION / "ruby-transcription.txt").write_text(
    "\n".join(f"{item['base']}\t{item['reading']}" for item in RUBY) + "\n", encoding="utf-8"
)
manifest = {
    "authored_date": "2026-09-07",
    "provenance": "Agent-authored synthetic Japanese teaching sentences; no customer data or extracted book text.",
    "body_columns_in_reading_order": BODY,
    "target_transcription": "Body text only; ruby stored separately, not inserted into prose.",
    "ruby": RUBY,
    "font": {"file": FONT.name, "sha256": hashlib.sha256(FONT.read_bytes()).hexdigest()},
    "pillow_version": pillow_version,
    "base_font_px": BASE_SIZE,
    "ruby_font_px": RUBY_SIZE,
    "vertical_character_step_px": STEP,
    "vertical_columns_x_right_to_left": COLUMN_X,
    "dpi_metadata": 300,
    "layout_limitations": "Simplified glyph-by-glyph layout; no full JIS typography engine, historic glyphs, skew, blur, handwriting or mixed-direction page tested.",
    "images": {name: {"width": image.width, "height": image.height, "sha256": hashlib.sha256((DESTINATION / name).read_bytes()).hexdigest()} for name, image in images.items()},
}
(DESTINATION / "sample-manifest.json").write_text(json.dumps(manifest, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
print(json.dumps({"generated": list(images), "body_codepoints_without_whitespace": len("".join(BODY)), "pillow": pillow_version}))
