# -*- coding: utf-8 -*-
"""Український текст для Level 2 A12 — «Перше Різдво».

Зимова розсилка, чотири історії: Захарій та Єлисавета, Марія та Гавриїл,
народження Івана, народження Ісуса. Той самий матеріал, що й у Level3_A12,
але для молодших: більший кегль, менше тексту, більше малюнків.

Ключі — `p<сторінка>b<блок>`, як їх дає `extract.py`. Специфікації:
    {'flow': ...}    — абзац з автопереносом ({sN} перемикає стиль)
    {'lines': [...]} — зберегти сітку рядків: рядок → сегменти (текст, стиль[, x])
    {'drop': True}   — тільки стерти

Цитати — переклад Огієнка. Імена за Огієнком: `Захарій` (не Захарія),
`Ангол` (не ангел), `Єлисавета`, `Гавриїл`, `Іван`.

Не перекладається: бренд `bibletime`, `bes`, `www.besweb.com`, реєстраційні
дані, номери сторінок, бокси балів, імена персонажів (B.E.S., Q, Pause,
Beam). Маркер завдання лишається «Q:».

Чотири головоломки не переживають перекладу — їх складено наново:

* стор. 3 — кросворд на чотири імені. Англійський зчеплений через `A`/`E`
  у GABRIEL; у `ГАВРИЇЛ` немає ні `І` (там `Ї`), ні `С`, тож ІСУС до нього
  не чіпляється взагалі. Напрямки довелося відпустити (в оригіналі два
  вниз, два впоперек) — інакше зв'язної сітки немає;
* стор. 4 — золотий вірш «по крапках». Шрифт `SassoonInfantDtB` кирилиці
  не має, крапки малює `puzzlekit.dotted_text()`;
* стор. 5 — акростих із малюнків: `JOHN` (jug, owl, hat, nail) → `ІВАН`
  (індик, відро, ананас, ножиці). Малюнки нові, CC0, див.
  `data/pictures/README.md`;
* стор. 8 — сітка-акростих. `MANGER` (ясла) українською — `ЯСЛА`, чотири
  літери на шість запитань. Замість того щоб різати запитання (а з ними
  й бали), ключове слово змінено на **РІЗДВО**: шість літер, кожна є у
  своїй відповіді, і для грудневої розсилки воно доречніше за «ясла».
"""
import json
import os

from lessons import MARKS_ROW_UP, marks_bonus, wrapped_lines

TR = {}
POST = []
WIPES = []

HERE = os.path.dirname(os.path.abspath(__file__))
RED = (0.917, 0.317, 0.353)          # #ea515a — фірмовий колір рівня 2

with open(os.path.join(HERE, 'work', 'Level2_A12', 'template.json'),
          encoding='utf-8') as _fh:
    _TPL = json.load(_fh)
IDX = {f"p{p['page']}b{b['i']}": b for p in _TPL for b in p['blocks']}

# Золоті вірші в цьому буклеті не надруковані — у боксі лише посилання,
# вірш дитина знаходить у своїй Біблії. Тож звіряти є що лише там, де
# вірш процитовано в самому уроці.
#
# Пунктирний вірш зі стор. 4 (Луки 1:37) сюди не потрапляє: він не в `TR`,
# а малюється в `POST` (`dotted_text`), і звірка читає специфікації, а не
# сторінку. Його текст звірено вручну по `bible.verse('Луки 1:37')`.
QUOTES = [
    ('p1b14', 'Луки 1:13', 'почута молитва твоя'),
    ('p2b17', 'Луки 1:34', 'Як же станеться це'),
    ('вірш по крапках, стор. 4', 'Луки 1:37'),
]

# Розбіжності з Огієнком, які ухвалив Редактор. Не помилка, а рішення —
# звірка лишає попередження й не спиняє збірку (правило замовника від
# 7 вересня 2026: слово Редактора важливіше за дослівність).
QUOTES_EDITOR = ['вірш по крапках, стор. 4']


def Q(key, *text_lines, qs=0, ts=1, tail=()):
    """«Q:» — окремий рядок шаблону на спільній базовій лінії (§2.4)."""
    TR[key] = {'lines': [[('Q:', qs)]] + [[(t, ts)] for t in text_lines]
               + [[seg] for seg in tail]}


def rows(key, *text_lines, s=0):
    TR[key] = {'lines': [[(t, s)] for t in text_lines]}


def head(page, block, big=False, with_name=False):
    """Шапка сторінок: bible|time, підпис рівня, номер серії."""
    lines = []
    if with_name:
        lines.append([("Ім'я:", 0)])
    i = 1 if with_name else 0
    lines.append([('bible', i), ('time', i + 1)])
    if big:                       # обкладинка має ще й www у шапці
        lines.append([('www.besweb.com', i + 2)])
        lines.append([('Рівень 2 — біблійні історії', i + 3)])
        lines.append([('A12', i + 4)])
    else:
        lines.append([('Рівень 2 — біблійні історії', i + 2)])
        lines.append([('A12', i + 3)])
    TR[f'p{page}b{block}'] = {'lines': lines}


def story(key, n, title, s0=0, s1=1):
    TR[key] = {'lines': [[(f'ІСТОРІЯ {n}:', s0), (f' {title}', s1)]]}


# Написи в намальованих боксах («ЧИТАЙ», «ЗОЛОТИЙ ВІРШ») центруються на
# боксі й міряються по його правому краю: «ЗОЛОТИЙ ВІРШ:» на 35 % ширший
# за «KEY VERSE:», а бокс намальований — його не розсунеш.
KV_BOX = (471.1, 538.1)
READ_BOX = (399.6, 466.7)
BOX_PAD = 1.5


def keyverse(key, ref, box=KV_BOX):
    TR[key] = {'lines': [[('ЗОЛОТИЙ ВІРШ:', 0)], [(ref, 1)],
                         [('Попроси когось', 2)],
                         [('допомогти знайти його.', 2)]],
               'center': True, 'right': box[1] - BOX_PAD}


def read(key, ref, box=READ_BOX):
    TR[key] = {'lines': [[('ЧИТАЙ:', 0)], [(ref, 1)]],
               'center': True, 'right': box[1] - BOX_PAD}


def marks(key, text):
    """Бокс балів. Не перекладається, але ключ мусить бути."""
    TR[key] = {'lines': [[(text, 0)]]}


# ═══════════════════════════════════════════════════════════ сторінка 1
rows('p0b0', 'Впиши тут своє імʼя та адресу.', 'Вік:', "Ім'я:", 'Адреса:')
for _i, _t in ((1, 'Вік:'), (2, "Ім'я:"), (3, 'Адреса:')):
    TR['p0b0']['lines'][_i] = [(_t, 1)]
rows('p0b1', 'Вчитель:')
head(0, 2, big=True)
TR['p0b3'] = {'lines': [[('Рівень 2', 0)]]}
# Підписи під фігурками центруються під СВОЄЮ фігуркою (правило від
# 3 вересня 2026): `center: True` ставить рядок на середину відповідного
# англійського спана, а той уже стоїть під фігуркою.
TR['p0b4'] = {'center': True, 'lines': [
    [('B.E.S.', 0)], [('мудрий друг', 1)],
    [('Q', 0)], [('ставить', 1)], [('запитання', 1)]]}
TR['p0b5'] = {'center': True, 'lines': [
    [('Pause', 0)], [('любить', 1)], [('подумати', 1)]]}
TR['p0b6'] = {'center': True, 'lines': [
    [('Beam', 0)], [('друг, який', 1)], [('підбадьорює', 1)]]}
story('p0b43', 1, 'Захарій та Єлисавета')
TR['p0b44'] = {'center': True, 'lines': [[('Бог відповідає на молитву', 0)]]}
keyverse('p0b46', 'Луки 1:13')
read('p0b48', 'Луки 1:5-25')
marks('p0b49', '/ 3')
marks('p0b50', '/ 6')
TR['p0b51'] = {'flow': (
    'Захарій та його дружина Єлисавета дуже сумували. Вони дуже хотіли дитину. '
    'Так довго вони молилися й просили Бога про немовля. Тепер вони були старі, '
    'і здавалося, що Єлисавета вже не може мати дитини.')}
TR['p0b52'] = {'flow': 'Одного дня була черга Захарія служити в храмі.'}
Q('p0b53', 'Підпиши під малюнками імена чоловіка й жінки та назву місця,',
  'де він служив.')
TR['p0b56'] = {'flow': (
    'Раптом зʼявився Ангол Господній. Захарій дуже злякався. Ангол сказав: '
    '"Не бійся, Захаріє, бо почута молитва твоя. Твоя дружина Єлисавета '
    'породить тобі сина, і даси йому ймення Іван".')}
Q('p0b57', 'Впиши пропущені слова — те, що сказав Ангол.')

# ── напис у хмаринці, стор. 1 ────────────────────────────────────────────
# Чотири рядки, центровані в овалі (57.4 … 504.2). Пропуск — ГРУПА
# підкреслень на літеру: «д __ __ …» це «дружина» без першої літери.
BALLOON_CX = (57.4 + 504.2) / 2


def centred(key, lines, style, cx, ys=None, size=None):
    """Рядки, центровані на осі `cx`: сегмент із порахованим `x`.

    `center: True` тут не годиться — воно центрує на центрі ВІДПОВІДНОГО
    оригінального спана, а англійський рядок іншої ширини й стоїть інакше.
    """
    import fitz
    from lessons import FONTFILES
    st = IDX[key]['styles'][style]
    fnt = fitz.Font(fontfile=FONTFILES[st['font']])
    size = size or st['size']
    out = []
    for i, text in enumerate(lines):
        if text is None:
            out.append(None)
            continue
        seg = (text, style, cx - fnt.text_length(text, size) / 2)
        opts = {'segs': [seg]}
        if ys:
            opts['y'] = ys[i]
        if size != st['size']:
            opts['size'] = size
        out.append(opts if len(opts) > 1 else [seg])
    TR[key] = {'lines': out}


centred('p0b58', ['І д __ __ __ __ __ __ твоя'], 0, BALLOON_CX)
centred('p0b59', ['Єлисавета с __ __ __ породить тобі,'], 0, BALLOON_CX)
centred('p0b60', ['а ти даси йому'], 0, BALLOON_CX)
centred('p0b61', ['ймення І __ __ __ .'], 0, BALLOON_CX)

# ═══════════════════════════════════════════════════════════ сторінка 2
rows('p1b0', 'www.besweb.com')
TR['p1b1'] = {'lines': [[('УСЬОГО:', 0)]]}
head(1, 2)
marks('p1b3', '/ 5')
marks('p1b4', '/ 6')
TR['p1b5'] = {'flow': (
    'Ангол пояснив, що це немовля буде особливим. Бог використає його, щоб '
    'багато людей відвернулися від злого й повірили Богові.')}
TR['p1b6'] = {'flow': (
    'Захарій не міг повірити в те, що чув. Він і його дружина були надто '
    'старі, щоб мати дитину. Про це він і сказав Анголові.')}
TR['p1b7'] = {'flow': (
    'Тоді Ангол Гавриїл сказав Захарієві, що за невіру він не зможе '
    'говорити, аж поки немовля народиться.')}
TR['p1b8'] = {'lines': [
    [('Q:', 0)],
    [('Постав галочку (', 1), ('✓', 2), (') або хрестик (', 1), ('✗', 2),
     (') біля кожного речення,', 1)],
    [('щоб показати, ПРАВИЛЬНЕ воно чи НЕПРАВИЛЬНЕ:', 1)]]}
# Квадратик для позначки стоїть на x = 369, тож рядок мусить скінчитися
# раніше. Англійський у цю межу вкладався, дослівний український — ні.
TICK_RIGHT = 365.0
for _k, _t in (('p1b9', 'Захарій сказав, що дружина надто стара для дитини.'),
               ('p1b10', 'Захарій повірив Анголові.'),
               ('p1b11', 'Гавриїл сказав, що Захарій осліпне.')):
    TR[_k] = {'right': TICK_RIGHT, 'lines': [[(_t, 0)]]}
TR['p1b12'] = {'flow': (
    'Коли Захарій вийшов із храму, він не міг говорити до людей. Усі '
    'подумали, що він бачив видіння.')}
TR['p1b13'] = {'flow': (
    'Незабаром Єлисавета чекала дитину. Слова Ангола справдилися!')}

# ── контурний напис, стор. 2 ─────────────────────────────────────────────
# Четвертий елемент сегмента вмикає режим обведення саме для цього рядка:
# у блоці є ще й звичайний текст завдання.
import fitz                                                    # noqa: E402
from lessons import FONTFILES                                  # noqa: E402

_BLACK = fitz.Font(fontfile=FONTFILES['Arial-Black'])
OUT_CX = (56.7 + 521.1) / 2


def _out(text, size=48.0, cx=OUT_CX):
    return cx - _BLACK.text_length(text, size) / 2


TR['p1b14'] = {'border': 0.5, 'lines': [
    [('Q:', 0)],
    [('Слова Ангола до Захарія були такі:', 1)],
    [('"Почута', 2, _out('"Почута'), 1)],
    [('молитва твоя."', 2, _out('молитва твоя."'), 1)]]}
TR['p1b15'] = {'lines': [[('Луки 1:13', 0), ('   Розфарбуй слова.', 1)]]}
TR['p1b16'] = {'flow': (
    'Біблія каже, що Бог завжди чує наші молитви. Він хоче, щоб ми вірили: '
    'Він на них відповість.')}
TR['p1b39'] = {'center': True, 'lines': [
    [('Чому Бог', 0)], [('покарав', 0)],
    [('Захарія', 0)], [('мовчанням?', 0)]]}
TR['p1b40'] = {'center': True, 'lines': [
    [('Він засумнівався', 0)], [('в Божій силі, Q!', 0)],
    [('Слід було хвалити', 0)], [('Бога за відповідь', 0)],
    [('на молитви!', 0)]]}

# ═══════════════════════════════════════════════════════════ сторінка 3
rows('p2b0', 'www.besweb.com')
head(2, 1, with_name=True)
story('p2b2', 2, 'Марія та Гавриїл')
TR['p2b3'] = {'center': True, 'lines': [[('Марія вірить Божому слову', 0)]]}
keyverse('p2b5', 'Луки 1:37')
read('p2b7', 'Луки 1:26-38')
marks('p2b8', '/ 8')
marks('p2b9', '/ 3')
TR['p2b10'] = {'flow': (
    'То був радісний час: Захарій та Єлисавета чекали дитину, а тепер Ангол '
    'Гавриїл мав звістити ще одне.')}
TR['p2b11'] = {'flow': (
    'Цього разу той самий Ангол прийшов до Марії, родички Єлисавети. Марія '
    'не була заміжня, але Ангол пояснив, що й вона матиме Сина.')}
TR['p2b12'] = {'flow': (
    'Йому мали дати імʼя Ісус, і Його називатимуть Сином Божим.')}
Q('p2b13', 'Скористайся підказками й упиши імена в сітку.')
TR['p2b15'] = {'flow': (
    'Марія здивувалася зі слів Гавриїла. "Як же станеться це, — спитала '
    'вона, — коли мужа не знаю?"')}
Q('p2b16', 'Розфарбуй літери')
TR['p2b17'] = {'render': 1, 'border': 0.5, 'lines': [
    [('"Як же', 0, _out('"Як же'))],
    [('станеться це?"', 0, _out('станеться це?"'))]]}
TR['p2b18'] = {'flow': (
    'Ангол пояснив, що на неї зійде Бог Дух Святий. Станеться чудо, і її '
    'Дитя буде Сином Божим.')}
for _k in ('p2b19', 'p2b20', 'p2b21'):
    TR[_k] = {'drop': True}                   # номери старої сітки

# ═══════════════════════════════════════════════════════════ сторінка 4
rows('p3b0', 'www.besweb.com')
TR['p3b1'] = {'lines': [[('УСЬОГО:', 0)]]}
head(3, 2)
marks('p3b3', '/6')
marks('p3b4', '/3')
# Вірш (рядки 2-4) малюється крапками в `POST`, тут його немає.
TR['p3b5'] = {'lines': [
    [('Q:', 0)],
    [("З'єднай крапки й вивчи золотий вірш, який допомагає зрозуміти,", 1)],
    [('як сталося це чудо.', 1)],
    None, None, None]}
rows('p3b6', 'Луки 1:37')
TR['p3b7'] = {'flow': (
    'Марія повірила всьому, що сказав Ангол. Як не схоже на Захарія, який '
    'засумнівався в Ангольській звістці!')}
TR['p3b8'] = {'flow': (
    'Марія була готова прийняти Божий задум і стати матірʼю цього '
    'особливого Дитяти.')}
Q('p3b9', 'Напиши ТАК або НІ після кожного речення,',
  'щоб показати, правильне воно чи ні.')
rows('p3b10', 'Марія засумнівалася в Анголові.')
rows('p3b11', 'На неї мав зійти Бог Дух Святий.')
rows('p3b12', 'Марія радо виконала Божу волю.')
TR['p3b13'] = {'flow': (
    'Марія була готова прийняти Божу волю для свого життя. Певно, багато '
    'хто не повірив би її розповіді.')}
TR['p3b14'] = {'flow': (
    'Та вона повністю довірилася Богові. Саме до цього Біблія закликає '
    'кожного з нас.')}
TR['p3b22'] = {'center': True, 'lines': [
    [('Коли знаєш, що Бог', 0)], [('може робити велике,', 0)],
    [('страх відступає!', 0)]]}

# ═══════════════════════════════════════════════════════════ сторінка 5
rows('p4b0', 'www.besweb.com')
head(4, 1, with_name=True)
story('p4b2', 3, 'Народження Івана')
TR['p4b3'] = {'center': True, 'lines': [[('Бог виконує Свої обіцянки', 0)]]}
keyverse('p4b5', 'Луки 1:76')
read('p4b7', 'Луки 1:57-80')
marks('p4b8', '/ 2')
marks('p4b9', '/ 3')
TR['p4b10'] = {'flow': (
    'Нарешті в Єлисавети народився син. Це був той син, якого Бог обіцяв '
    'через Ангола Гавриїла.')}
TR['p4b11'] = {'flow': (
    'Рідні та сусіди прийшли привітати їх, і всі раділи.')}
TR['p4b12'] = {'flow': (
    'Коли хлопчикові виповнювалося вісім днів, йому давали імʼя. Часто сина '
    'називали іменем батька. Усі хотіли назвати немовля Захарієм, але '
    'Єлисавета сказала: "Ні!"')}
Q('p4b13', 'Запиши першу літеру назви кожного предмета — і дізнаєшся, яке',
  'імʼя хотіла дати синові його мати.')
Q('p4b20', 'Намалюй немовля на руках у Захарія.', 'Розфарбуй малюнок.')
TR['p4b21'] = {'flow': (
    'Захарій не міг говорити, зате міг писати. Він написав: "Іван імення '
    'йому".')}
Q('p4b22', 'Розфарбуй правильне закінчення', 'речення.')
rows('p4b23', 'Він не міг відповісти, бо:')
# Варіанти центруються в СВОЇХ намальованих рамках (57.2 … 258.5):
# англійські якорі підігнані під англійську ширину, і найдовший
# український рядок виїжджав за рамку.
OPT_BOX = (57.2, 258.5)
_OPT_FONT = fitz.Font(fontfile=FONTFILES['Arial-BoldMT'])


def _opt(key, text, tail=None):
    x = (OPT_BOX[0] + OPT_BOX[1] - _OPT_FONT.text_length(text, 12.0)) / 2
    segs = [(text, 0, x)]
    if tail:
        segs.append(tail)
    TR[key] = {'lines': [segs]}


_opt('p4b24', 'не міг зважитися.')
_opt('p4b25', 'не міг говорити.')
# У цьому блоці живе ще й бокс балів — його координата задана явно,
# бо після довшого варіанта якір оригіналу вже не спрацьовує.
_opt('p4b26', 'хотів, щоб вирішила Єлисавета.', ('/ 1', 1, 540.9))

# ═══════════════════════════════════════════════════════════ сторінка 6
rows('p5b0', 'www.besweb.com')
TR['p5b1'] = {'lines': [[('УСЬОГО:', 0)]]}
head(5, 2)
marks('p5b3', '/ 4')
Q('p5b4', 'Впиши пропущені літери,', 'які написав Захарій.')
TR['p5b5'] = {'flow': (
    'Щойно Захарій написав ці слова, він зміг говорити. Він почав '
    'прославляти Бога.')}
TR['p5b6'] = {'flow': (
    'Усі дивувалися з того, що сталося, і чутка про це рознеслася по всьому '
    'краю. Люди зрозуміли, що ця дитина особлива і що Бог буде з нею '
    'по-особливому.')}
Q('p5b7', 'Впиши пропущені слова в поданому абзаці.')

# ── абзац із пропусками, стор. 6 ─────────────────────────────────────────
# Шість слів, як в оригіналі (бали /6). Ліва межа спільна для всіх рядків
# і лежить в опції `x`, а не третім елементом сегмента: тоді правка
# Редактора застосовується сама (§2.5).
CLOZE_X = 100.2


def _cloze(key, *segs):
    TR[key] = {'right': 470.0, 'lines': [{'segs': list(segs), 'x': CLOZE_X}]}


_cloze('p5b8', ('Коли ', 0), ('З __ __ __ __ __ __', 1), (' ', 0),
       ('н __ __ __ __ __ __', 1), (', що дитині', 0))
_cloze('p5b9', ('дадуть імʼя ', 0), ('І __ __ __', 1),
       (' , його уста розкрилися', 0))
_cloze('p5b10', ('і він зміг ', 0), ('г __ __ __ __ __ __ __', 1),
       (' . Він прославив ', 0), ('Б __ __ __', 1), (' ,', 0))
# «здивовані», а не «вражені» — правка Редактора від 7 вересня. Слово
# довше на дві літери, тож і рисочок на дві більше: клітинка ставиться на
# кожну ГРУПУ підкреслень, і їх має бути стільки, скільки літер у слові
# без першої. Рядок від цього доходить до 440 pt при межі 470 — тобто
# ужимати кегль не доводиться й він лишається однаковим з рештою абзацу.
_cloze('p5b11', ('а сусіди були ', 0), ('з __ __ __ __ __ __ __ __', 1),
       (' з усього, що сталося.', 0))

TR['p5b12'] = {'flow': (
    'Прославляючи Бога, Захарій сказав, що одного дня його син стане '
    'пророком Господнім. Він також приготує дорогу для приходу Ісуса.')}
Q('p5b13', 'Обведи правильну відповідь на ці запитання:')
TR['p5b14'] = {'lines': [[('1) Хто прославив Бога?   ', 0),
                          ('Захарій / Гавриїл / Іван', 1)]]}
TR['p5b15'] = {'lines': [[('2) Хто мав стати пророком Господнім?   ', 0),
                          ('Захарій / Гавриїл / Іван', 1)]]}
TR['p5b16'] = {'flow': (
    'Іван виріс, і все це справдилося — саме так, як сказав Бог!')}

# ── напис на сувої, стор. 6 ──────────────────────────────────────────────
# «Іван імення йому» (Луки 1:63) — три слова там, де в оригіналі чотири.
# Рядки сідають симетрично навколо середини первісного чотирирядка, а не
# звисають від верхнього (§2.5, `wrapped_lines`).
# Площина сувою між валиками — приблизно 327 … 432 pt, тобто 105 pt.
# При кеглі оригіналу (18 pt) рядок «і __ __ __ __ __» має 130 pt і
# лягає просто на правий валик; 14 pt дають 101 pt і вкладаються.
SCROLL_CX, SCROLL_SIZE = 379.5, 14.0
_SCROLL_Y = [186.0, 207.6, 229.2, None]
centred('p5b17', ['І __ __ __', 'і __ __ __ __ __', 'й __ __ __ .', None],
        0, SCROLL_CX, ys=_SCROLL_Y, size=SCROLL_SIZE)
marks('p5b18', '/ 6')
marks('p5b19', '/ 4')
TR['p5b30'] = {'center': True, 'lines': [
    [('Божим словам завжди можна', 0)], [('довіряти. Тому Біблія — така', 0)],
    [('особлива книга.', 0)]]}

# ═══════════════════════════════════════════════════════════ сторінка 7
rows('p6b0', 'www.besweb.com')
head(6, 1, with_name=True)
story('p6b2', 4, 'Народження Ісуса')
TR['p6b3'] = {'center': True,
              'lines': [[('Бог дає Свого Сина нам за Спасителя', 0)]]}
keyverse('p6b5', 'Луки 2:7')
read('p6b7', 'Луки 2:1-7')
marks('p6b8', '/ 4')
TR['p6b9'] = {'flow': (
    'Коли Марія чекала народження Дитяти, від римського імператора вийшов '
    'наказ: усім треба піти до міста, де вони народилися, і записатися.')}
TR['p6b10'] = {'flow': (
    'Це означало, що Марії та Йосипу доведеться вирушити в далеку подорож '
    'до Віфлеєма, який ще звуть "містом Давидовим".')}
Q('p6b11', 'Підпиши на карті місто, де жила Марія, і місце, куди вони',
  'подорожували.')
TR['p6b12'] = {'flow': (
    'Коли вони прийшли до Віфлеєма, там було так людно, що годі було '
    'знайти місце для ночівлі. У заїзді місця не було, та врешті вони '
    'знайшли, де спинитися.')}
TR['p6b13'] = {'flow': (
    'Тут і народився Ісус. Марія мала тільки пелюшки, щоб сповити Його, а '
    'тоді поклала Його в ясла, куди зазвичай кладуть корм худобі. Ніхто б '
    'не подумав, що покладене тут Немовля таке важливе.')}
TR['p6b15'] = {'center': True, 'right': 243.1 - BOX_PAD,
               'lines': [[('Земля Ізраїльська', 0)]]}
rows('p6b16', 'Н __ __ __ __ __ __')
rows('p6b17', 'В __ __ __ __ __ __')
rows('p6b18', 'Середземне', 'море')
TR['p6b19'] = {'lines': [[('Мертве', 0)], [('море', 0)], [('80 км', 0)]]}
TR['p6b27'] = {'center': True, 'lines': [
    [('Дивно подумати, що Син', 0)], [('Божий прийшов на землю так', 0)],
    [('просто. Він розуміє твої турботи', 0)], [('й тривоги. Може, поговориш', 0)],
    [('із Ним сьогодні?', 0)]]}

# ═══════════════════════════════════════════════════════════ сторінка 8
TR['p7b0'] = {'lines': [[('Бали', 0), (' (заповнює вчитель)', 1)]]}
rows('p7b1', 'ІСТОРІЯ 1:')
rows('p7b2', 'ІСТОРІЯ 2:')
rows('p7b3', 'ІСТОРІЯ 3:')
rows('p7b4', 'ІСТОРІЯ 4:')
# «Разом» переїхало на порожній рядок вище; на його місце `marks_bonus()`
# домальовує «Додаткові бали» (правило від 3 вересня 2026).
TR['p7b5'] = {'lines': [{'segs': [('Разом', 0)], 'y': MARKS_ROW_UP}]}
rows('p7b6', 'Загалом')
TR['p7b7'] = {'lines': [[('Коментар учителя:', 0),
                         ('Надішли свої уроки на адресу:', 0, 471.7)]]}
TR['p7b8'] = {'lines': [[('РАЗОМ:', 0)]]}
TR['p7b9'] = {'lines': [
    [('©', 0), (' Bible Educational Services. Visit ', 1),
     ('www.besweb.com', 2), (' or phone +44 (0) 28 6632 2462 for information.', 1)],
    [('Registered Charity UK CIO 1186004', 1)],
    [('РІВЕНЬ 2 A12', 3)],
    [('12/2025', 4)]]}
marks('p7b10', '/ 4')
marks('p7b11', '/12')
Q('p7b12', 'Впиши відповіді на запитання в сітку.')
Q('p7b16', 'Впиши пропущені літери.')
TR['p7b17'] = {'lines': [[('Ісус — це ', 0), ('С __ __   Б __ __ __ __', 1),
                          (' .', 0)]]}
TR['p7b18'] = {'lines': [[('Біблія каже, що Ісус прийшов як наш ', 0),
                          ('С __ __ __ __ __ __ __ __', 1), (' .', 0)]]}
TR['p7b14'] = {'flow': (
    'Щодня у світі народжуються сотні немовлят, але Біблія навчає, що такого '
    'Немовляти не було ніколи. Це Дитя — Син Божий.')}
TR['p7b15'] = {'flow': (
    'Різдво — це час, коли християни спиняються й дякують Богові за Його '
    'велику любов: Він послав Свого Сина у світ, щоб Той став нашим '
    'Спасителем.')}
for _n in range(19, 31):                      # літери й номери старої сітки
    TR[f'p7b{_n}'] = {'drop': True}


# ═══════════════════════════════════════════════════ головоломки
from puzzlekit import (cover, draw_grid, dotted_text, extent,   # noqa: E402
                       number, place_crossword)

PICS = os.path.join(os.path.dirname(HERE), 'data', 'pictures')
CLUE_X = 56.7


def _at(text, style, x=CLUE_X):
    """Рядок із заданою лівою межею.

    `x` кладеться в ОПЦІЮ рядка, а не третім елементом сегмента: третій
    елемент означає «координату пораховано з ширини цього тексту», і
    `edits.py` такі рядки навмисно не чіпає (§2.5).
    """
    return {'segs': [(text, style)], 'x': x}


# ── кросворд, стор. 3 ────────────────────────────────────────────────────
# Напрямки НЕ закріплені, на відміну від оригіналу (два вниз, два впоперек).
# Причина не в лінощах: у `ГАВРИЇЛ` немає ні `І` (там `Ї`), ні `С`, тож при
# закріплених напрямках `ІСУС` не чіпляється до жодного горизонтального
# слова — зв'язної сітки не існує взагалі. Підказки в макеті йдуть суцільним
# списком без заголовків, тож перестановка нічого не ламає; заголовки
# «По вертикалі/По горизонталі» додано за правилом від 3 вересня 2026.
CROSS = ['МАРІЯ', 'ІСУС', 'ГАВРИЇЛ', 'СИН']
CROSS_BOX = (262.0, 424.0, 508.0, 554.0)
CROSS_COVER = (268.0, 423.0, 476.0, 556.0)

_cross_placed, _cross_missed = place_crossword(CROSS, seed=0)
_cross_nums, _cross_across, _cross_down = number(_cross_placed)
_CN = {p.word: n for n, p in _cross_across + _cross_down}

CLUE = {
    'МАРІЯ':   'Як звали родичку Єлисавети?',
    'ІСУС':    'Яке імʼя мали дати Немовляті?',
    'ГАВРИЇЛ': 'Як звали Ангола?',
    # «Божий», а не «Божим» — правка Редактора від 7 вересня. Підказка
    # називає ВІДПОВІДЬ, яку дитина впише в сітку, а в сітці слово стоїть у
    # називному: `СИН`. Текст узято дослівно, як його написав Редактор, —
    # інакше його ж правка з панелі мовчки перезаписала б мій варіант.
    'СИН':     'Немовля назвуть С __ __  Божий.',
}


def _clue_lines(title, words):
    out = [_at(title, 0)]
    for w in sorted(words, key=lambda w: _CN[w]):
        out.append(_at(f'{_CN[w]}.  {CLUE[w]}', 0))
    return out


_down_words = [p.word for _n, p in _cross_down]
_across_words = [p.word for _n, p in _cross_across]
# Порожній рядок між групами підказок — правка Редактора від 7 вересня.
# Панель такого зробити не могла: правка міняла КІЛЬКІСТЬ рядків, а це вже
# верстка, не текст, і `edits.classify` її відхиляв.
#
# Рядок ПОРОЖНІЙ, а не пропущений (`None`). Різниця важлива саме для
# панелі: `None` не рахується за рядок, тож збережена правка Редактора на
# сім рядків відхилялася б і далі — назавжди. З порожнім рядком їх сім і в
# макеті, і в правці, тож наступного разу вона застосується сама.
TR['p2b14'] = {'right': 262.0, 'lines': (
    _clue_lines('По вертикалі:', _down_words)
    + [_at('', 0)]
    + _clue_lines('По горизонталі:', _across_words))}


# ── золотий вірш по крапках, стор. 4 ─────────────────────────────────────
# Луки 1:37. В Огієнка — «неможливої ЖАДНОЇ речі», і це не описка: у Новому
# Завіті «жадн-» трапляється 44 рази й жодного разу в Старому (перевірено
# 4 вересня 2026). Але Редактор попросив «жодної» — 7 вересня тут, і те
# саме раніше в Level3_A12. Слово Редактора важливіше за дослівність
# (рішення замовника від 7 вересня), тож друкуємо «жодної».
#
# Правку довелося робити тут, а не в панелі: вірш «по крапках» — не блок
# верстки, а малюнок, і в панелі його тексту немає. Редактор описав місце
# словами в зауваженні до сусіднього блока.
#
# Щоб розбіжність не лишалася невидимою, вірш оголошено в `DRAWN_TEXT` і
# звіряється нарівні з рештою — а `QUOTES_EDITOR` каже, що вона ухвалена.
ROUND = FONTFILES['SassoonInfantDtB']
_ROUND_FONT = fitz.Font(fontfile=ROUND)
DOT_SIZE = 58.0
DOT_CX = (56.7 + 520.0) / 2
DOTTED = [('"Бо для Бога', 196.2), ('нема неможливої', 255.8),
          ('жодної речі!"', 325.4)]
DRAWN_TEXT = {'вірш по крапках, стор. 4': ' '.join(t for t, _y in DOTTED)}


# ── акростих із малюнків, стор. 5 ────────────────────────────────────────
# JOHN (jug, owl, hat, nail) українською не працює: назви предметів інші.
# ІВАН — індик, відро, ананас, ножиці. Усі чотири малюнки нові (CC0,
# Openclipart), бо жодна з англійських світлин українською не дає потрібної
# літери. Перевірка на однозначність (§2.5): «відро», «ананас», «ножиці»
# дитина назве саме так; «індик» — єдине місце, де лишається ризик почути
# «птах», і воно позначене в звіті.
ACRO_BAND = (390.4, 432.9)
ACRO_WIPE = (83.0, 388.0, 257.0, 434.6)
ACRO_CELLS = [94.2, 137.9, 181.6, 225.2]      # ліві краї клітинок відповіді
ACRO_PICS = ['turkey.png', 'bucket.png', 'pineapple.png', 'scissors.png']
CELL_W = 24.5
CELL_TOP = 435.8


# ── сітка-акростих, стор. 8 ──────────────────────────────────────────────
# `MANGER` (ясла) українською — `ЯСЛА`: чотири літери на шість запитань.
# Різати запитання не можна (з ними поїдуть бали /12), тож ключове слово
# змінено на **РІЗДВО**. Кожна літера є у своїй відповіді, а для грудневої
# розсилки слово доречніше за «ясла».
GRID_ANSWERS = [
    ('МАРІЯ',   3, 'Як звали матір Ісуса?'),
    ('ГАЛІЛЕЯ', 4, 'У якій частині країни був Назарет?'),
    ('НАЗАРЕТ', 3, 'Як називалося рідне місто Марії?'),
    ('ЗАЇЗД',   5, 'Що було переповнене?'),
    ('ВІФЛЕЄМ', 1, 'У якому місті народився Ісус?'),
    ('ЙОСИП',   2, 'Як звали чоловіка Марії?'),
]
GRID_KEY = ''.join(w[i - 1] for w, i, _c in GRID_ANSWERS)      # РІЗДВО
GRID_X0 = 347.7                     # ліві краї стовпчиків — як в оригіналі
GRID_CELL = 24.5
GRID_KEY_Y = 180.0                  # верх ключового рядка
GRID_COVER = (344.0, 90.0, 498.0, 344.0)

TR['p7b13'] = {'right': 330.0, 'lines': (
    [_at('По вертикалі:', 0)]
    + [_at(f'{i + 1}.  {c}', 0) for i, (_w, _p, c) in enumerate(GRID_ANSWERS)])}


def _grid_geom():
    """-> (верх сітки, [(x, верх стовпчика, довжина слова)])."""
    above = max(p - 1 for _w, p, _c in GRID_ANSWERS)
    top = GRID_KEY_Y - above * GRID_CELL
    cols = []
    for i, (w, p, _c) in enumerate(GRID_ANSWERS):
        cols.append((GRID_X0 + i * GRID_CELL,
                     GRID_KEY_Y - (p - 1) * GRID_CELL, len(w)))
    return top, cols


def apply_covers(page):
    """Стару графіку закриваємо ДО набору (§2.1), окремою фазою."""
    rects = {2: [CROSS_COVER], 4: [ACRO_WIPE], 7: [GRID_COVER]}.get(page.number)
    if rects:
        cover(page, rects, WIPES)


def _fit(box, placed):
    x0, y0, x1, y1 = box
    _, _, rows_n, cols_n = extent(placed)
    cell = min((x1 - x0) / cols_n, (y1 - y0) / rows_n)
    ox = x0 + ((x1 - x0) - cell * cols_n) / 2
    oy = y0 + ((y1 - y0) - cell * rows_n) / 2
    return (ox, oy), cell, rows_n, cols_n


def _draw_puzzles(doc, only=None):
    def want(pno):
        return only is None or pno in only

    if only is None:
        marks_bonus(doc[7])           # рядок «Додаткові бали»

    if want(2):
        origin, cell, r, c = _fit(CROSS_BOX, _cross_placed)
        draw_grid(doc[2], _cross_placed, _cross_nums, origin, cell, RED)
        print(f'  стор. 3: кросворд {r}×{c}, клітинка {cell:.1f} pt'
              + (f', НЕ ЗВʼЯЗАНО: {_cross_missed}' if _cross_missed else ''))

    if want(3):
        page = doc[3]
        for text, y in DOTTED:
            x = DOT_CX - _ROUND_FONT.text_length(text, DOT_SIZE) / 2
            if not dotted_text(page, (x, y), text, 'uaDot', ROUND, DOT_SIZE):
                print(f'  !! пунктир не застосовано до {text!r}')
        print('  стор. 4: золотий вірш по крапках — 3 рядки')

    if want(4):
        page = doc[4]
        y0, y1 = ACRO_BAND
        for cx, pic in zip(ACRO_CELLS, ACRO_PICS):
            box = fitz.Rect(cx + CELL_W / 2 - 21.0, y0,
                            cx + CELL_W / 2 + 21.0, y1)
            page.insert_image(box, filename=os.path.join(PICS, pic),
                              keep_proportion=True)
        print('  стор. 5: акростих ІВАН — %d малюнків' % len(ACRO_PICS))

    if want(7):
        page = doc[7]
        top, cols = _grid_geom()
        page.insert_font(fontname='uaB', fontfile=FONTFILES['Arial-BoldMT'])
        fnt = fitz.Font(fontfile=FONTFILES['Arial-BoldMT'])
        for i, (x, ytop, n) in enumerate(cols):
            for k in range(n):
                y = ytop + k * GRID_CELL
                page.draw_rect(fitz.Rect(x, y, x + GRID_CELL, y + GRID_CELL),
                               color=RED, width=0.8)
            # номер стовпчика — над його верхньою клітинкою
            page.insert_text((x + 4.0, ytop - 4.0), str(i + 1),
                             fontname='uaB', fontsize=12.0, color=(0, 0, 0))
            # підказана літера ключового слова, як `MANGER` в оригіналі
            ch = GRID_KEY[i]
            size = 18.0
            page.insert_text(
                (x + (GRID_CELL - fnt.text_length(ch, size)) / 2,
                 GRID_KEY_Y + GRID_CELL * 0.76), ch,
                fontname='uaB', fontsize=size, color=(0, 0, 0))
        print('  стор. 8: сітка-акростих %s, %d стовпчиків, низ %.0f pt'
              % (GRID_KEY, len(cols), max(y + n * GRID_CELL
                                          for _x, y, n in cols)))


POST.append(_draw_puzzles)


# ── праві межі абзаців ───────────────────────────────────────────────────
# §2.4, правило 1: якщо праворуч від абзацу стоїть ілюстрація чи хмаринка,
# український текст (він довший) заповзе під неї. Ознака — вузький bbox.
for _k, _v in TR.items():
    if 'flow' in _v and 'right' not in _v:
        _r = IDX[_k]['bbox'][2]
        if _r < 480:
            _v['right'] = _r + 2.0


# ═══════════════════════════════════════════════ поля, оголошені уроком
#
# Клітинки акростиха — рівні квадрати під малюнками. Детектор їх не бачить
# (в англійському оригіналі це завдання теж падає в чекбокс «виконано»):
# ряд однакових порожніх квадратів без рамки-відповіді поруч не має ознаки,
# за яку можна зачепитися. Тому урок оголошує ці поля сам.
EXTRA_FIELDS = [
    {'page': 4, 'task': 1, 'type': 'char',
     'rect': [cx + 1.5, CELL_TOP + 1.5,
              cx + CELL_W - 1.5, CELL_TOP + CELL_W - 1.5]}
    for cx in ACRO_CELLS
]


# ── навмисне зростання блоків (§1.5, клас GROW) ──────────────────────────
# Не «підіймаємо поріг», а називаємо поіменно ті блоки, де зростання —
# рішення, а не дефект:
#
#   p2b14  — до чотирьох підказок кросворда додано два заголовки
#            («По вертикалі:», «По горизонталі:», правило від 3 вересня);
#   p2b17  — контурний напис центрується на колонці, а не на англійському
#            якорі: український рядок довший і при старому якорі виїхав би
#            праворуч за поле сторінки;
#   p5b9, p5b11 — рядки абзацу з пропусками вирівняні по спільній лівій
#            межі (100.2). В оригіналі вони стояли «сходинкою» під різні
#            англійські довжини; з українськими це виглядало б випадково.
GROW_OK = ['p2b14', 'p2b17', 'p5b9', 'p5b11']


# ═══════════════════════════════════════════════ екранна версія
#
# Блок, який в інтерактиві звучить інакше, ніж на друку. Збирається командою
# `build.py Level2_A12 --screen`; друкований PDF від цього не змінюється,
# панель показує обидва тексти.
#
# На папері дитина обводить олівцем крапки. На екрані крапок не обведеш —
# зате контурні літери вірша стають полями-заливками (тип `paint`), тобто
# завдання лишається тим самим за суттю: провести рукою по кожній літері.
# Тому й інструкція на екрані інша.
SCREEN_TEXT = {
    'p3b5': ('Q:\nРозфарбуй літери золотого вірша, який допомагає зрозуміти,'
             '\nяк сталося це чудо.'),
}
