"""Extract the dialogues of « À vos marques, prêts… parlez ! » 3 and 5 from the OCR text:
title, French sentences, English sentences, section-A listening questions with the answer key, and the matching recordings.
    python tools/parlez_extract.py   ->  Book/L4/parlez_data.json"""
import os, re, json, difflib, unicodedata
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
L4 = os.path.join(ROOT, "Book", "L4")
AR = re.compile(r"[\u0600-\u06FF]")
HEAD = re.compile(r"^#*\s*Dialogue\s+(\d+)\s*$")


def norm(s):
    s = unicodedata.normalize("NFD", s.lower().replace("’", "'"))
    s = "".join(c for c in s if unicodedata.category(c) != "Mn")
    return re.sub(r"[^a-z0-9' ]+", " ", s).split()


def dialogues(lines, key_at):
    out, i = {}, 0
    while i < key_at:
        m = HEAD.match(lines[i].strip())
        if not m or i + 1 >= key_at or lines[i + 1].strip().startswith(("A.", "|", "#")):
            i += 1
            continue
        n = int(m.group(1)); title = lines[i + 1].strip().strip("#").strip()
        j = i + 2; block = []
        while j < key_at and not lines[j].startswith("#") and not HEAD.match(lines[j].strip()):
            raw = lines[j].strip()
            t = raw.lstrip("–—-").strip()
            if t and not AR.search(t):
                block.append((t, raw[:1] in "–—-"))     # (sentence, starts a new speaker turn)
            j += 1
        if len(block) >= 2 and len(block) % 2 == 0 and n not in out:
            h = len(block) // 2
            spk, who = [], 0
            for k, (_, new_turn) in enumerate(block[:h]):
                if new_turn and k:
                    who = 1 - who
                spk.append(who)
            out[n] = dict(n=n, title=title, fr=[b[0] for b in block[:h]], en=[b[0] for b in block[h:]], speaker=spk, start=j)
        i = j
    return out


OPT = re.compile(r"(?:^|\s{2,}|\t)([a-e])\.\s*(.+?)(?=(?:\s{2,}|\t)[a-e]\.\s|$)")


def questions(lines, start, stop):
    """Section A: '2. ... 1- question / a. … e.' -> [(group, sub, question, [options])]"""
    qs, g, cur = [], None, None
    for ln in lines[start:stop]:
        s = ln.strip()
        if re.match(r"^#*\s*B\.\s*Lecture", s):
            break
        m = re.match(r"^([2-9])\.\s*(.*)", s)
        if m:
            g = int(m.group(1)); cur = None
            continue
        m = re.match(r"^(\d+)-\s*(.+)", s)
        if m and g:
            cur = dict(g=g, sub=int(m.group(1)), q=m.group(2).strip(), opts=[])
            qs.append(cur)
            continue
        if cur is not None and re.match(r"^[a-e]\.\s", s):
            for _, txt in OPT.findall(" " * 2 + s):
                cur["opts"].append(re.sub(r"[¹²³⁴⁵'’]+$", "", txt.strip()).strip())
    return [q for q in qs if 3 <= len(q["opts"]) <= 5]


def keys(lines, key_at):
    """Answer key: per dialogue n -> {(group, sub): 'b'} for single-letter answers of section A."""
    out, n, inA = {}, None, False
    for ln in lines[key_at:]:
        s = ln.strip()
        m = re.match(r"^#*\s*Dialogue\s+(\d+)", s)
        if m:
            n = int(m.group(1)); out.setdefault(n, {}); inA = False
            continue
        if "Compréhension orale" in s:
            inA = True
            continue
        if s.startswith("**") or s.startswith("#"):
            inA = False
            continue
        m = re.match(r"^([2-9])\.\s*(.+)", s)
        if inA and n and m:
            for sub, ans in re.findall(r"(\d+)-\s*:\s*([^–]+)", m.group(2)):
                letters = re.findall(r"\b([a-e])\.", ans)
                if len(letters) == 1 and "/" not in ans and ")" not in ans:
                    out[n][(int(m.group(1)), int(sub))] = letters[0]
    return out


def audio_index(slug):
    data = json.load(open(os.path.join(L4, f"audio_{slug}.json"), encoding="utf-8"))
    for a in data:
        a["words"] = norm(a["text"])
    return data


def best_clip(sentence, clips, used):
    """Recording whose transcript is this sentence (short clip); returns (file, score)."""
    w = norm(sentence)
    best = (None, 0)
    for a in clips:
        if a["file"] in used or a["seconds"] > 12:
            continue
        r = difflib.SequenceMatcher(None, w, a["words"][:len(w) + 3]).ratio()
        if r > best[1]:
            best = (a["file"], r)
    return best


def dialogue_clip(fr, clips):
    """Long recording of the whole dialogue (French then English…)."""
    w = norm(" ".join(fr))
    best = (None, 0)
    for a in clips:
        if a["seconds"] <= 12:
            continue
        r = difflib.SequenceMatcher(None, w, a["words"][:len(w) + 2]).ratio()
        if r > best[1]:
            best = (a["file"], r)
    return best


def book(slug):
    lines = open(os.path.join(L4, f"{slug}_clean.txt"), encoding="utf-8").read().split("\n")
    key_at = max(i for i, l in enumerate(lines) if re.match(r"^#*\s*Corrigés\s*$", l.strip()))
    ds, ks, clips = dialogues(lines, key_at), keys(lines, key_at), audio_index(slug)
    used, starts = set(), sorted(d["start"] for d in ds.values())
    for n, d in sorted(ds.items()):
        nxt = min([x for x in starts if x > d["start"]] + [key_at])
        qs = questions(lines, d["start"], nxt)
        for q in qs:
            q["answer"] = ks.get(n, {}).get((q["g"], q["sub"]))
        d["questions"] = [q for q in qs if q["answer"] and ord(q["answer"]) - 97 < len(q["opts"])]
        d["audio"] = []
        for s in d["fr"]:
            f, r = best_clip(s, clips, used)
            if r >= 0.75:
                used.add(f)
            d["audio"].append(f if r >= 0.75 else None)
        f, r = dialogue_clip(d["fr"], clips)
        d["dialogue_audio"] = f if r >= 0.6 else None
        del d["start"]
    return [ds[n] for n in sorted(ds)]


if __name__ == "__main__":
    out = {s: book(s) for s in ("parlez3", "parlez5")}
    json.dump(out, open(os.path.join(L4, "parlez_data.json"), "w", encoding="utf-8"), ensure_ascii=False, indent=1)
    for s, ds in out.items():
        print(s, len(ds), "dialogues;", sum(len(d["questions"]) for d in ds), "questions;",
              sum(a is not None for d in ds for a in d["audio"]), "/", sum(len(d["fr"]) for d in ds), "sentences with audio;",
              sum(d["dialogue_audio"] is not None for d in ds), "dialogue recordings")
