#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Рендер сторінок уроку в PNG для редактора областей (`editor/regions.html`).

PDF.js у редакторі не потрібен: сторінку віддаємо звичайною картинкою, а
редактор обводить області поверх неї. Щоб файл із контурами не залежав від
того, у якому масштабі його малювали, коефіцієнт перерахунку «піксель → пункт»
має бути відомий редакторові. Найпростіший спосіб передати його без сервера й
без fetch() (file:// блокує читання сусідніх файлів) — **записати в ім'я
файлу**:

    page_<стем PDF>_p<стор>_<dpi>dpi.png

Редактор розбирає ім'я і сам обчислює `pt_per_px = 72 / dpi`. Так само працює
і завантаження картинки через <input type=file> на планшеті.

Поруч пишеться `pages.json` — покажчик сторінок для перемикача в панелі
(на випадок, коли каталог віддається без списку файлів). Він **не** є
джерелом правди про області: панель, якщо може, читає список каталогу і
бачить свіжі `regions_p<NN>_<task>.json` без перегенерації покажчика.

Запуск:
    .venv/bin/python editor/make_page.py forms/Level2_UA_form_v07.pdf 16
    .venv/bin/python editor/make_page.py forms/Level2_UA_form_v07.pdf --all
    .venv/bin/python editor/make_page.py forms/Level2_UA_form_v07.pdf --pages 3-8,16
    .venv/bin/python editor/make_page.py forms/Level2_UA_form_v07.pdf 16 --dpi 200
"""
import argparse
import json
import os
import re
import sys

import fitz

HERE = os.path.dirname(os.path.abspath(__file__))


def parse_pages(spec, npages):
    """'all' | '16' | '3-8,16' -> відсортований перелік номерів сторінок з 1."""
    spec = (spec or "").strip().lower()
    if spec in ("all", "*", "усі", "всі"):
        return list(range(1, npages + 1))
    out = set()
    for part in spec.split(","):
        part = part.strip()
        if not part:
            continue
        m = re.fullmatch(r"(\d+)\s*-\s*(\d+)", part)
        if m:
            a, b = int(m.group(1)), int(m.group(2))
            out.update(range(min(a, b), max(a, b) + 1))
        else:
            out.add(int(part))
    bad = [p for p in out if p < 1 or p > npages]
    if bad:
        raise SystemExit("у документі %d сторінок, немає: %s"
                         % (npages, ", ".join(map(str, sorted(bad)))))
    return sorted(out)


def stem_of(pdf):
    return re.sub(r"[^A-Za-z0-9_.-]", "_",
                  os.path.splitext(os.path.basename(pdf))[0])


def write_index(out_dir, stem, dpi, entries, npages):
    """Покажчик сторінок. Зливається з наявним, щоб не загубити інші PDF/dpi."""
    path = os.path.join(out_dir, "pages.json")
    doc = {"format": "bibletime-pages/1", "docs": {}}
    if os.path.exists(path):
        try:
            old = json.load(open(path, encoding="utf-8"))
            if isinstance(old.get("docs"), dict):
                doc["docs"] = old["docs"]
        except Exception:
            pass
    d = doc["docs"].setdefault(stem, {"pdf": stem + ".pdf", "n_pages": npages,
                                      "pages": {}})
    d["n_pages"] = npages
    d["dpi"] = dpi
    for pno, fn in entries:
        d["pages"][str(pno)] = os.path.basename(fn)
    doc["docs"][stem] = d
    with open(path, "w", encoding="utf-8") as f:
        json.dump(doc, f, ensure_ascii=False, indent=1, sort_keys=True)
    return path


def main(argv=None):
    ap = argparse.ArgumentParser()
    ap.add_argument("pdf")
    ap.add_argument("page", type=int, nargs="?",
                    help="номер сторінки, з 1 (можна замість --pages)")
    ap.add_argument("--pages", help="'all' або '3-8,16'")
    ap.add_argument("--all", action="store_true", help="усі сторінки документа")
    ap.add_argument("--dpi", type=int, default=150,
                    help="роздільна здатність рендера (типово 150)")
    ap.add_argument("--out", default=HERE, help="каталог для PNG")
    ap.add_argument("--force", action="store_true",
                    help="перемалювати навіть наявні PNG")
    a = ap.parse_args(argv)

    doc = fitz.open(a.pdf)
    if a.all:
        spec = "all"
    elif a.pages:
        spec = a.pages
    elif a.page is not None:
        spec = str(a.page)
    else:
        raise SystemExit("вкажіть сторінку, --pages або --all")
    pages = parse_pages(spec, doc.page_count)

    stem = stem_of(a.pdf)
    os.makedirs(a.out, exist_ok=True)
    entries = []
    for pno in pages:
        fn = os.path.join(a.out, "page_%s_p%02d_%ddpi.png" % (stem, pno, a.dpi))
        if os.path.exists(fn) and not a.force:
            print("%s  (є, пропущено)" % fn)
        else:
            pix = doc[pno - 1].get_pixmap(dpi=a.dpi)
            pix.save(fn)
            print("%s  %dx%d px, сторінка %.1fx%.1f pt, pt_per_px=%.6f"
                  % (fn, pix.width, pix.height, doc[pno - 1].rect.width,
                     doc[pno - 1].rect.height, 72.0 / a.dpi))
        entries.append((pno, fn))

    idx = write_index(a.out, stem, a.dpi, entries, doc.page_count)
    print("покажчик -> %s  (%d сторінок з %d)"
          % (idx, len(entries), doc.page_count))
    doc.close()
    return 0


if __name__ == "__main__":
    sys.exit(main())
