#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Покажчик тексту сторінки для коректури в панелі.

Панель показує сторінку картинкою, а Редактор має бачити **текст**: що
написано українською, що стояло в оригіналі, і де саме на сторінці цей
шматок лежить. Усе це вже є в проєкті, розпізнавати нічого не треба:

* `work/<буклет>/layout.json` — прямокутник кожного видрукуваного рядка з
  ключем блока. Це точні дані з моменту малювання (§1.5), а не реконструкція;
* `work/<буклет>/template.json` — англійський оригінал, розібраний на спани;
* `tr_<буклет>.py` — український текст, яким його набирали.

На виході — `editor/text_<стем PNG>.json`: по блоку на запис, координати в
**пунктах** (панель ділить на `pt_per_px` так само, як для областей).

    .venv/bin/python ua_build/text_index.py Level4_A12 \\
        --png-stem Level4_A12_UA_v01

`--png-stem` — стем сторінкових PNG у панелі. Він не збігається з іменем
друкованої версії: панель показує **інтерактивний** урок (`_UA_v01`), а
`layout.json` лишився від збірки друку (`_UA_v10`). Геометрія в них та сама —
інтерактив це той самий друк плюс віджети, — а імена різні, тож стем
задається явно.
"""
import argparse
import json
import os
import re
import sys

HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)

from lessons import Lesson                                     # noqa: E402

STYLE_RE = re.compile(r'\{s\d+\}')


def spec_text(spec):
    """Український текст блока з його специфікації — так, як його набирали."""
    if not isinstance(spec, dict) or spec.get('drop'):
        return None
    if 'flow' in spec:
        return STYLE_RE.sub('', spec['flow'])
    if 'lines' in spec:
        out = []
        for entry in spec['lines']:
            if entry is None:
                continue
            segs = entry['segs'] if isinstance(entry, dict) else entry
            out.append(' '.join(str(s[0]) for s in segs).strip())
        return '\n'.join(out).strip()
    return None


def block_text(blk, flow=False):
    """Англійський оригінал блока з шаблону.

    Рядки в шаблоні розбиті версткою, а не змістом: у суцільному абзаці
    речення переламане посередині. Для абзаца (`flow`) склеюємо назад у
    суцільний текст — коректор порівнює зміст, і рвані рядки лише заважають.
    Там, де рядки значущі (перелік, підказки, рядки таблиці), лишаємо як є.
    """
    lines = [''.join(sp['text'] for sp in ln['spans']).strip()
             for ln in blk['lines']]
    return (' '.join(lines) if flow else '\n'.join(lines)).strip()


def union(rects):
    xs0 = min(r[0] for r in rects); ys0 = min(r[1] for r in rects)
    xs1 = max(r[2] for r in rects); ys1 = max(r[3] for r in rects)
    return [round(xs0, 1), round(ys0, 1), round(xs1, 1), round(ys1, 1)]


def build(stem, png_stem):
    lesson = Lesson(stem)
    tpl = json.load(open(lesson.template, encoding='utf-8'))
    layout_path = os.path.join(lesson.work, 'layout.json')
    if not os.path.exists(layout_path):
        raise SystemExit('немає %s — спершу збери урок (build.py %s)'
                         % (layout_path, stem))
    layout = json.load(open(layout_path, encoding='utf-8'))
    tr = __import__('tr_%s' % stem).TR
    # Покажчик має описувати те, що НА СТОРІНЦІ, а не те, що в файлі
    # перекладу. Постійні правки Редактора накладаються при збірці, тож
    # без них панель показувала б старий текст поруч зі свіжою картинкою —
    # рівно те, що Редактор і помітив.
    from edits import apply_overlay
    apply_overlay(tr, stem)

    # Блоки, які на екрані звучать інакше, ніж на друку (`SCREEN_TEXT`).
    # Панель показує саме екранну сторінку, тож `uk` — це екранний текст, а
    # друкований іде окремим полем: інакше Редактор вичитував би одну
    # версію, а друкарня отримувала б іншу, і ніхто б цього не побачив.
    from edits import load_screen_overlay
    screen = dict(getattr(__import__('tr_%s' % stem), 'SCREEN_TEXT', {}))
    screen.update(load_screen_overlay(stem))
    print_uk = {k: spec_text(tr.get(k)) for k in screen}

    blocks = []
    for pg in tpl:
        for blk in pg['blocks']:
            key = 'p%db%d' % (pg['page'], blk['i'])
            drawn = layout.get(key)
            spec = tr.get(key)
            # Три різні стани, і плутати їх не можна:
            #   ok       — блок перемальовано, є український текст;
            #   dropped  — блок навмисно стерто (стара сітка, службовий
            #              уламок): на сторінці там тепер порожньо, і
            #              підсвічувати його як «не перекладено» — брехня;
            #   original — блок не чіпали, там і досі англійський оригінал.
            #              Здебільшого це службові написи (бокс балів,
            #              адреса сайту), але сюди ж потрапить і пропущений
            #              при перекладі шматок — саме те, що має впадати
            #              Редакторові в око.
            if drawn:
                status = 'ok'
            elif isinstance(spec, dict) and spec.get('drop'):
                status = 'dropped'
            else:
                status = 'original'
            # Рід блока й кількість рядків потрібні панелі: у блоці типу
            # `lines` сітка рядків значуща (кожен рядок стоїть на своїй
            # базовій лінії), і правка, яка міняє їхню кількість, лягає в
            # макет не сама собою. Хай Редактор бачить це відразу, а не
            # дізнається, коли правку не вдасться застосувати.
            kind = None
            if isinstance(spec, dict):
                kind = 'flow' if 'flow' in spec else ('lines' if 'lines' in spec
                                                      else None)
            uk = spec_text(spec)
            extra = {}
            if key in screen:
                uk = screen[key]
                extra = {'print_uk': print_uk[key]}
            blocks.append({
                'key': key,
                'page': pg['page'] + 1,
                'rect_pt': union(drawn) if drawn else [round(v, 1)
                                                       for v in blk['bbox']],
                'en': block_text(blk, flow=(kind == 'flow')),
                'uk': uk,
                'kind': kind,
                'lines': len(uk.split('\n')) if uk else 0,
                'status': status,
                **extra,
            })

    blocks.sort(key=lambda b: (b['page'], b['rect_pt'][1], b['rect_pt'][0]))
    return {
        'format': 'bibletime-text/1',
        'lesson': stem,
        'stem': png_stem,
        'pages': len(tpl),
        'blocks': blocks,
    }


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument('stem', help='напр. Level4_A12')
    ap.add_argument('--png-stem', required=True,
                    help='стем сторінкових PNG у панелі, напр. Level4_A12_UA_v01')
    ap.add_argument('--out', default=None)
    a = ap.parse_args()

    doc = build(a.stem, a.png_stem)
    out = a.out or os.path.join(os.path.dirname(HERE), 'editor',
                                'text_%s.json' % a.png_stem)
    with open(out, 'w', encoding='utf-8') as fh:
        json.dump(doc, fh, ensure_ascii=False, indent=1)

    n = {}
    for b in doc['blocks']:
        n[b['status']] = n.get(b['status'], 0) + 1
    print('%s: блоків %d — перекладено %d, стерто %d, з оригіналом %d; стор. %d'
          % (a.png_stem, len(doc['blocks']), n.get('ok', 0),
             n.get('dropped', 0), n.get('original', 0), doc['pages']))
    print('->', out)


if __name__ == '__main__':
    main()
