#!/usr/bin/env python3
"""Batch re-OCR of all image-based books → improved/ searchable PDFs (200 dpi).

Classifies each PDF in originals/; only books that contain real scanned page
images are processed (digital-text books like CC/BG are skipped — they have no
images to re-OCR). reocr_book.py handles per-page: image pages get fresh
tesseract-5 OCR, digital pages pass through untouched.

Runs several books in parallel. Skips books already present in improved/.
"""
import fitz, os, subprocess, glob
from concurrent.futures import ThreadPoolExecutor, as_completed

BASE = os.path.dirname(os.path.abspath(__file__))
ORIG = os.path.join(BASE, "originals")
OUT = os.path.join(BASE, "improved")
DPI = "200"
WORKERS = 4
os.makedirs(OUT, exist_ok=True)

def has_scanned_pages(f):
    d = fitz.open(f); n = d.page_count
    idxs = [int(n * r) for r in (0.2, 0.35, 0.5, 0.65, 0.8)]
    hits = 0
    for i in idxs:
        p = d[i]; A = p.rect.width * p.rect.height
        if not A:
            continue
        for b in p.get_text("rawdict")["blocks"]:
            if b.get("type") == 1:
                bb = b["bbox"]
                if (bb[2]-bb[0])*(bb[3]-bb[1]) > 0.45 * A:
                    hits += 1; break
    d.close()
    return hits >= 1  # any sampled page is a scanned image

def process(f):
    name = os.path.basename(f)
    outp = os.path.join(OUT, name)
    if os.path.exists(outp):
        return f"SKIP (exists) {name}"
    tmp = outp + ".part"
    r = subprocess.run(["python3", os.path.join(BASE, "reocr_book.py"), f, tmp, DPI],
                       capture_output=True, text=True)
    if os.path.exists(tmp):
        os.rename(tmp, outp)
        return r.stdout.strip() or f"done {name}"
    return f"FAIL {name}: {r.stderr[-200:]}"

def main():
    books = [f for f in sorted(glob.glob(os.path.join(ORIG, "*.pdf"))) if has_scanned_pages(f)]
    print(f"Image-based books to re-OCR: {len(books)}", flush=True)
    for b in books:
        print("  -", os.path.basename(b), flush=True)
    print("=" * 50, flush=True)
    done = 0
    with ThreadPoolExecutor(max_workers=WORKERS) as ex:
        futs = {ex.submit(process, b): b for b in books}
        for fut in as_completed(futs):
            done += 1
            print(f"[{done}/{len(books)}] {fut.result()}", flush=True)
    print("ALL DONE", flush=True)

if __name__ == "__main__":
    main()
