#!/usr/bin/env python3
"""Auto-derive each book's page range inside master.pdf by anchoring the scan
(gold) text into the master's full text. Outputs master_ranges.json.

Because master.pdf has no TOC and totally different pagination from the old
14k-page vedabase1.pdf, we locate each book by content: find an early scan
phrase and a late scan phrase inside the master → start/end pages.
"""
import fitz, re, unicodedata, json, bisect, os
import compare as c

BASE = os.path.dirname(os.path.abspath(__file__))
MASTER = os.path.join(BASE, "master.pdf")

def fold(s):
    s = unicodedata.normalize('NFKD', s)
    return ' '.join(''.join(ch for ch in s if not unicodedata.combining(ch)).lower().split())

def main():
    M = fitz.open(MASTER)
    offs = []; buf = []; pos = 0
    for i in range(M.page_count):
        pt = fold(M[i].get_text())
        offs.append(pos); buf.append(pt); pos += len(pt) + 1
    full = ' '.join(buf)
    def c2p(cp): return bisect.bisect_right(offs, cp) - 1

    ranges = {}
    report = []
    for k, b in c.BOOKS.items():
        if k.startswith("letters_"):
            continue
        try:
            gold = fold(c.extract_chapter_text(
                c.resolve_orig(b['original'] if isinstance(b['original'], str) else b['original'][0]),
                b.get('orig_start_page', 0), b.get('orig_end_page', 99999), strip_headers=True))
        except Exception as e:
            report.append((k, "ERR", str(e)[:40])); continue
        gw = gold.split()
        if len(gw) < 30:
            report.append((k, "SHORT", f"{len(gw)}w")); continue
        # Anchor on many INTERIOR points (10%..90%) to skip front/back matter and
        # tolerate changed passages. Take the envelope of found positions.
        hits = []
        for frac in [i/100 for i in range(8, 93, 3)]:  # 8%..92%, ~29 probes
            idx = int(len(gw) * frac)
            probe = ' '.join(gw[idx:idx+7])
            if len(probe) < 15: continue
            p = full.find(probe)
            if p >= 0: hits.append(p)
        if len(hits) < 3:
            report.append((k, "NO-ANCHOR", f"{len(hits)} anclas")); continue
        sp, ep = min(hits), max(hits)
        p1, p2 = c2p(sp), c2p(ep)
        # pad a little to cover the book's true edges beyond the interior anchors
        p1 = max(0, p1 - 2); p2 = min(M.page_count - 1, p2 + 2)
        ranges[k] = {"vedabase_start": p1, "vedabase_end": p2 + 1}
        report.append((k, "OK", f"p{p1}-{p2} ({p2-p1+1}pp, {len(hits)} anclas)"))

    json.dump(ranges, open(os.path.join(BASE, "master_ranges.json"), "w"), indent=1)
    ok = sum(1 for r in report if r[1] == "OK")
    print(f"Rangos derivados: {ok}/{len(report)} libros anclados en master.pdf\n")
    for k, st, info in sorted(report, key=lambda r: (r[1] != "OK", r[0])):
        if st != "OK":
            print(f"  ⚠ {k:9s} {st}  {info}")
    print(f"\n(OK: {ok}; ver master_ranges.json)")

if __name__ == "__main__":
    main()
