# -*- coding: utf-8 -*-
"""Звіт для Редактора по Level2_A12 у PDF.

Верстається тим самим Arial, що й буклети, щоб Редактор бачив звичний
для програми набір. Розмітка мінімальна: `**жирний**`, заголовки, списки
й одна таблиця.
"""
import os
import re
import fitz

OUT = '/Users/pavlokulakovskiy/projects/BibleTime/interactive-pdf/data/zvit_Level2_A12.pdf'
FR = '/System/Library/Fonts/Supplemental/Arial.ttf'
FB = '/System/Library/Fonts/Supplemental/Arial Bold.ttf'
FI = '/System/Library/Fonts/Supplemental/Arial Italic.ttf'
FONTS = {'r': fitz.Font(fontfile=FR), 'b': fitz.Font(fontfile=FB),
         'i': fitz.Font(fontfile=FI)}
ALIAS = {'r': 'ar', 'b': 'ab', 'i': 'ai'}
FILES = {'r': FR, 'b': FB, 'i': FI}

W, H = 595.3, 841.9
L, R = 56.7, 538.6
TOP, BOT = 70.0, 782.0
RED = (0.917, 0.317, 0.353)
INK = (0.1, 0.1, 0.12)
GREY = (0.45, 0.45, 0.5)
RULE = (0.82, 0.82, 0.85)

doc = fitz.open()
page = None
y = 0.0
pageno = 0


def newpage():
    global page, y, pageno
    page = doc.new_page(width=W, height=H)
    for k, f in FILES.items():
        page.insert_font(fontname=ALIAS[k], fontfile=f)
    pageno += 1
    y = TOP
    if pageno > 1:
        page.insert_text((L, 44), 'Level2_A12 — звіт для Редактора',
                         fontname='ar', fontsize=8, color=GREY)
        page.draw_line(fitz.Point(L, 52), fitz.Point(R, 52),
                       color=RULE, width=0.6)


def space(v):
    global y
    if y + v > BOT:
        newpage()
    else:
        y += v


def rich(text):
    """`**жирний**` і `*курсив*` -> [(текст, стиль)]."""
    out, pos = [], 0
    for m in re.finditer(r'\*\*(.+?)\*\*|\*(.+?)\*', text):
        if m.start() > pos:
            out.append((text[pos:m.start()], 'r'))
        out.append((m.group(1), 'b') if m.group(1) else (m.group(2), 'i'))
        pos = m.end()
    if pos < len(text):
        out.append((text[pos:], 'r'))
    return out


def wrap(segs, size, width):
    """Розбити сегменти на рядки завширшки не більше `width`."""
    # Слово може складатися з кількох сегментів різного стилю —
    # «**М**а**Р**ія». Розривати його на межі сегмента не можна, тож
    # спершу збираємо АТОМИ (шматки без пробілів), а вже потім рядки.
    atoms, cur_atom = [], []
    for txt, st in segs:
        for part in re.split(r'(\s+)', txt):
            if not part:
                continue
            if part.isspace():
                if cur_atom:
                    atoms.append(cur_atom)
                    cur_atom = []
                atoms.append(None)          # пробіл
            else:
                cur_atom.append((part, st))
    if cur_atom:
        atoms.append(cur_atom)

    def awidth(a):
        return sum(FONTS[st].text_length(t, size) for t, st in a)

    lines, cur, w = [], [], 0.0
    sp = FONTS['r'].text_length(' ', size)
    for a in atoms:
        if a is None:
            if cur:
                cur.append((' ', 'r'))
                w += sp
            continue
        tw = awidth(a)
        if cur and w + tw > width:
            while cur and cur[-1][0].isspace():
                cur.pop()
            lines.append(cur)
            cur, w = list(a), tw
        else:
            cur.extend(a)
            w += tw
    if cur:
        while cur and cur[-1][0].isspace():
            cur.pop()
        lines.append(cur)
    return lines


def emit(lines, size, lead, x=L, colour=INK, first_dx=0.0):
    global y
    for i, line in enumerate(lines):
        if y + lead > BOT:
            newpage()
        pen = x + (first_dx if i == 0 else 0.0)
        for txt, st in line:
            page.insert_text((pen, y + size * 0.82), txt, fontname=ALIAS[st],
                             fontsize=size, color=colour)
            pen += FONTS[st].text_length(txt, size)
        y += lead


def para(text, size=10.0, lead=14.2, x=L, right=R, colour=INK, gap=7.0):
    emit(wrap(rich(text), size, right - x), size, lead, x, colour)
    space(gap)


def h1(text):
    global y
    space(2)
    if y + 30 > BOT:
        newpage()
    emit(wrap(rich(text), 19.0, R - L), 19.0, 23.0, colour=INK)
    space(3)
    page.draw_line(fitz.Point(L, y), fitz.Point(R, y), color=RED, width=1.6)
    space(14)


def h2(text):
    global y
    space(9)
    if y + 34 > BOT:
        newpage()
    emit(wrap([(text, 'b')], 12.5, R - L), 12.5, 16.0, colour=RED)
    space(5)


def bullet(text, marker='•', size=10.0, lead=14.2, indent=15.0):
    page_before = pageno
    emit(wrap(rich(text), size, R - L - indent), size, lead, L + indent)
    yy = y - lead * len(wrap(rich(text), size, R - L - indent))
    if pageno == page_before:
        page.insert_text((L + 3, yy + size * 0.82), marker,
                         fontname='ab', fontsize=size, color=RED)
    space(4)


def table(head, rows, widths, size=9.3, lead=12.6, pad=5.0):
    global y
    xs, x = [], L
    for w in widths:
        xs.append(x)
        x += w
    def row(cells, style, fill=None):
        global y
        cols = [wrap(rich(c) if style == 'r' else [(c, 'b')], size,
                     widths[i] - 2 * pad) for i, c in enumerate(cells)]
        hgt = max(len(c) for c in cols) * lead + 2 * pad - (lead - size) 
        if y + hgt > BOT:
            newpage()
        if fill:
            page.draw_rect(fitz.Rect(L, y, x, y + hgt), color=None, fill=fill)
        for i, lines in enumerate(cols):
            yy = y + pad
            for line in lines:
                pen = xs[i] + pad
                for txt, st in line:
                    page.insert_text((pen, yy + size * 0.82), txt,
                                     fontname=ALIAS[st], fontsize=size,
                                     color=INK)
                    pen += FONTS[st].text_length(txt, size)
                yy += lead
        y += hgt
        page.draw_line(fitz.Point(L, y), fitz.Point(x, y), color=RULE,
                       width=0.6)
    row(head, 'b', fill=(0.97, 0.94, 0.94))
    for r in rows:
        row(r, 'r')
    space(10)


# ────────────────────────────────────────────────────────────── зміст
newpage()
page.draw_rect(fitz.Rect(0, 0, W, 6), color=None, fill=RED)
y = 78
emit([[('bible', 'r')]], 21.0, 25.0, colour=RED)
y -= 25.0
page.insert_text((L + FONTS['r'].text_length('bible', 21.0), y + 21.0 * 0.82),
                 'time', fontname='ar', fontsize=21.0, color=INK)
y += 27.0
emit([[('Рівень 2 — біблійні історії · A12 «Перше Різдво»', 'r')]],
     9.5, 13.0, colour=GREY)
space(16)

h1('Level2_A12 готовий і вже в панелі')

para('**Level2_A12_UA_v04.pdf** (друк) і **Level2_A12_UA_v02.pdf** (інтерактив) — '
     '**231 поле**, круговий тест 222/222, цитати збігаються з Огієнком, '
     'геометричний контроль лишає самі оголошені зауваження. Чекбокс '
     '«виконано» **один** на весь буклет (намалюй і розфарбуй немовля).')

h2('Чотири головоломки, жодна не пережила перекладу')

table(['стор.', 'що було', 'що зроблено'],
      [['3', 'кросворд MARY / JESUS / GABRIEL / SON',
        'складено наново; **напрямки довелося відпустити** — у ГАВРИЇЛ немає '
        'ні «І» (там «Ї»), ні «С», тож ІСУС не чіпляється до жодного '
        'горизонтального слова, і зв’язної сітки при закріплених напрямках '
        'не існує взагалі'],
       ['4', 'золотий вірш «по крапках»',
        'Луки 1:37 намальовано крапками — англійський шрифт SassoonInfantDt '
        'кирилиці не має'],
       ['5', 'акростих JOHN — jug, owl, hat, nail',
        '**ІВАН** — індик, відро, ананас, ножиці'],
       ['8', 'сітка-акростих MANGER',
        'ключове слово змінено на **РІЗДВО**']],
      [42, 165, R - L - 42 - 165])

h2('Про сітку на стор. 8')

para('«Ясла» — чотири літери на шість запитань. Різати запитання не можна: '
     'з ними поїхали б бали /12, а це облік учителя. Тож змінено не сітку, а '
     'ключове слово — кожна літера **РІЗДВО** є у своїй відповіді: '
     '**М**а**Р**ія, гал**І**лея, на**З**арет, заїз**Д**, **В**іфлеєм, '
     'й**О**сип. Для грудневої розсилки воно й доречніше за «ясла».')

para('**Малюнки акростиха — уперше всі CC0** (Openclipart, автори названі). '
     'Питання ліцензій, відкрите на трьох малюнках Level3_A12, тут не '
     'виникає.')

h2('Три виправлення в конвеєрі')

para('Усі одного класу — код бачив лише один із двох випадків розкладки:')
bullet('варіанти вибору шукалися тільки в РЯД, тож три рамки одна під одною '
       '(«розфарбуй правильне закінчення») падали в чекбокс «виконано»;')
bullet('рамка всередині сувою ставала текстовим полем — порожній жовтий '
       'прямокутник посеред малюнка;')
bullet('звірка цитат порівнювала регістр і сварилася на верстку: напис '
       '«Почута молитва твоя.» відкриває речення з великої літери, а в '
       'Огієнка це слово стоїть посеред вірша.')
para('Level3_A12 і Level4_A12 від цих змін не зрушили — 233 і 186 полів, '
     'як були.', gap=4)

h2('Три речі на розсуд Редактора')

bullet('**«Індик»** — єдине слово акростиха, яке можна назвати інакше '
       '(«птах»). Перший малюнок, контурний і без кольору, я відкинув саме '
       'тому, що читався як голуб; поточний обрано за силуетом — хвіст '
       'віялом, борідка. Якщо діти казатимуть «птах», літеру «І» доведеться '
       'шукати заново: однозначних предметів на неї в українській дуже мало.',
       marker='1.')
bullet('**Три квадратики «галочка або хрестик» (стор. 2)** в інтерактиві '
       'стали незалежними чекбоксами — так велить правило про окремі '
       'квадрати. Але хрестика чекбокс не дає: позначене = правильне, '
       'порожнє = неправильне АБО не зроблене. Обійти списком вибору теж '
       'не вийде: самі знаки галочки й хрестика є лише в одному '
       'системному шрифті, а шрифт полів форми їх не має.', marker='2.')
bullet('**«жадної» в Луки 1:37 (стор. 4)** — лишено слово Огієнка. '
       'У Level3_A12 Редактор виправив його на «жодної»; тут рішення знову '
       'за ним, правка застосується з панелі одним натисканням.', marker='3.')

h2('Стан')

para('Усе запушено в репозиторій і розгорнуто — панель показує Level2_A12 '
     'четвертим буклетом. Наступний за планом — **Level1_A12**, потім '
     'найдорожчий Level0_A12.')

# підвал на кожній сторінці
for i, p in enumerate(doc, 1):
    p.insert_font(fontname='ar', fontfile=FR)
    p.insert_text((L, 806), '7 вересня 2026', fontname='ar', fontsize=8,
                  color=GREY)
    lab = '%d / %d' % (i, len(doc))
    p.insert_text((R - fitz.Font(fontfile=FR).text_length(lab, 8), 806), lab,
                  fontname='ar', fontsize=8, color=GREY)

doc.set_metadata({'title': 'Level2_A12 — звіт для Редактора',
                  'author': 'bibletime', 'subject': 'Рівень 2, серія A12'})
doc.subset_fonts(verbose=False)
doc.save(OUT, garbage=4, deflate=True)
print('->', OUT, os.path.getsize(OUT), 'байт,', len(doc), 'стор.')
