# -*- coding: utf-8 -*-
"""Unit 1 – L'alphabet (book pages 12–117): one interactive lesson per letter pair + a «Bilan» per chapter."""
import random
import unicodedata
from . import words as WD

ALPHA = "abcdefghijklmnopqrstuvwxyz"
SIMILAR = {"a": "oecd", "b": "dpqh", "c": "oeag", "d": "bpqa", "e": "acos", "f": "tlrk", "g": "qpyj", "h": "nbkm", "i": "ljt",
           "j": "igyp", "k": "hxf", "l": "itf", "m": "nwhu", "n": "mhur", "o": "aceq", "p": "qbdg", "q": "pbdg", "r": "nmv",
           "s": "zcg", "t": "fil", "u": "nvwm", "v": "uwy", "w": "vmu", "x": "kyz", "y": "vxg", "z": "sxn"}

CHAPTERS = [  # (chapter no, title, letter pairs, bilan dictation letters from the audio transcriptions p.234)
    (1, "L'alphabet A – F", ["ab", "cd", "ef"], list("ADFECB")),
    (2, "L'alphabet G – L", ["gh", "ij", "kl"], list("ILJGHK")),
    (3, "L'alphabet M – R", ["mn", "op", "qr"], list("RMQNOP")),
    (4, "L'alphabet S – X", ["st", "uv", "wx"], list("STWVXU")),
    (5, "L'alphabet Y – Z", ["yz"], list("RHBSZY")),
]

SONGS = {
    1: ("Compère Guilleri", "كومبير غيلري", [
        "Il était un p'tit homme / Qui s'appelait Guilleri, carabi",
        "Il s'en fut à la chasse / À la chasse aux perdrix, carabi",
        "Titi carabi, toto carabo, / Compère Guilleri.",
        "Te lairas-tu, te lairas-tu, / Te lairas-tu mouri ?",
        "Il monta sur un arbre / Pour voir ses chiens couri, carabi",
        "La branche vint à rompre / Et Guilleri tombit, carabi",
    ]),
    3: ("En passant par la Lorraine", "مروراً بلورين", [
        "En passant par la Lorraine, avec mes sabots,",
        "Rencontrai trois capitaines, avec mes sabots dondaine,",
        "Oh, oh, oh ! Avec mes sabots !",
        "Ils m'ont appelée vilaine, avec mes sabots,",
        "Je ne suis pas si vilaine, avec mes sabots dondaine,",
        "Puisque le fils du roi m'aime, avec mes sabots !",
    ]),
}


FUN_LETTER = {"ab": "b", "cd": "c", "ef": "f", "gh": "h", "ij": "j", "kl": "k", "mn": "n", "op": "o", "qr": "r", "st": "s", "uv": "u", "wx": "x", "yz": "y"}

# «Bilan – J'entoure les images qui contiennent le son …» (book pages 35, 59, 81-82, 104-105, 114-115)
BILAN_SOUNDS = {1: ("d", "b"), 2: ("i", "j"), 3: ("r", "o"), 4: ("g", "b"), 5: ("u", "r")}

# «Bilan – J'entoure la lettre … dans les mots illustrés» (book pages 36, 60, 80, 103, 114)
BILAN_SPOT = {
    1: ("e", ["cube", "menu", "farine", "datte", "banane", "cabane"]),
    2: ("e", ["banane", "Irène", "datte", "garde", "Hervé", "regarde", "René", "karaté"]),
    3: ("i", ["kaki", "Irène", "huit", "olive", "David", "farine", "Robin", "image"]),
    4: ("t", ["moto", "Victor", "Tom", "porte", "tomate", "nature", "Quentin", "karaté"]),
    5: ("c", ["coq", "Victor", "sac", "Oscar", "clé", "Nicole", "lac", "café"]),
}


def word_item(fr):
    """A word for «letter spot»: picture/meaning from the vocabulary when the word is known."""
    for k, w in WD.W.items():
        if w["fr"].lower() == fr.lower():
            return dict(word=fr, ar=w["ar"], **WD.pic(k))
    return dict(word=fr, ar="", emoji="🔤", img=None)


def strip(s):
    return "".join(c for c in unicodedata.normalize("NFD", s) if unicodedata.category(c) != "Mn").lower()


def has(key, letter):
    return letter in strip(WD.W[key]["fr"])


def pair_keys(letter):
    return [k for k, w in WD.W.items() if w.get("letter") == letter and not w.get("is_name")]


def name_key(letter):
    return "name_" + letter


def act(aid, typ, title, title_ar, instr, instr_ar, points, data):
    return dict(id=aid, type=typ, title=title, title_ar=title_ar, instr=instr, instr_ar=instr_ar, points=points, data=data)


def letter_cards(letters):
    out = []
    for l in letters:
        out.append(dict(kind="letter", upper=l.upper(), lower=l, tts=l, text=f"{l.upper()} {l}",
                        ar=f"الحرف {l.upper()}", note="لا يُنطق حرف H أبداً" if l == "h" else ""))
        for k in pair_keys(l) + [name_key(l)]:
            c = WD.card(k)
            c["kind"] = "word"
            c["tts"] = c["text"]
            out.append(c)
    return out


def hunt_grid(rng, target, rows=5, cols=5, n_target=7):
    cells = [target.upper() if i % 2 else target for i in range(n_target)]
    pool = SIMILAR[target] + ALPHA.replace(target, "")
    while len(cells) < rows * cols:
        c = rng.choice(pool[:4] if rng.random() < 0.6 else pool)
        cells.append(c.upper() if rng.random() < 0.4 else c)
    rng.shuffle(cells)
    return [cells[i * cols:(i + 1) * cols] for i in range(rows)]


def sound_pick(rng, letter, known, n_total=5):
    good = [k for k in known if has(k, letter)]
    bad = [k for k in known if not has(k, letter)]
    rng.shuffle(good)
    rng.shuffle(bad)
    n_good = min(len(good), 3 if len(good) >= 3 and rng.random() < 0.5 else 2)
    items = good[:n_good] + bad[:n_total - n_good]
    rng.shuffle(items)
    return dict(letter=letter, count=n_good, items=[dict(WD.card(k), correct=has(k, letter)) for k in items])


def fill_items(letters):
    items = []
    for l in letters:
        for k in pair_keys(l) + [name_key(l)]:
            w = WD.W[k]
            text = w["fr"]
            blanks = [i for i, ch in enumerate(text) if ch.isalpha() and strip(ch) in letters]
            if blanks:
                items.append(dict(key=k, art=w["art"], word=text, blanks=blanks, ar=w["ar"], **WD.pic(k)))
    return items


def spot_words(letter):
    fun = WD.FUN.get(letter)
    if fun:
        return [dict(word=fr, ar=ar, emoji=em, img=None) for fr, ar, em in fun]
    ks = [k for k in WD.W if WD.W[k].get("letter") and has(k, letter) and not WD.W[k].get("is_name")]
    return [dict(word=WD.W[k]["fr"], ar=WD.W[k]["ar"], **WD.pic(k)) for k in ks][:10]


def letter_choices(rng, letter, n=4):
    pool = list(SIMILAR[letter]) + [c for c in ALPHA if c != letter]
    out = [letter]
    for c in pool:
        if c not in out:
            out.append(c)
        if len(out) == n:
            break
    rng.shuffle(out)
    return out


def pair_lesson(chap, pair, known_before):
    rng = random.Random(f"u1-{pair}")
    a, b = pair[0], pair[1]
    keys = pair_keys(a) + pair_keys(b)
    known = known_before + keys
    lid = f"u1-{pair}"
    A, B = a.upper(), b.upper()
    acts = [
        act(lid + "-observe", "flashcards", "J'observe, j'écoute et je retiens", "أشاهد وأستمع وأتذكّر",
            "J'écoute chaque lettre et chaque mot, puis je répète.", "استمع إلى كل حرف وكل كلمة ثم كرّرها بصوت عالٍ.", 10,
            dict(cards=letter_cards([a, b]))),
        act(lid + "-trace", "trace", "J'écris les lettres", "أكتب الحروف",
            f"Je trace {A} {a} {B} {b} avec mon doigt.", "ارسم الحروف بإصبعك فوق الخطوط.", 10,
            dict(letters=[A, a, B, b])),
        act(lid + "-hunt", "letter_hunt", f"J'entoure les {a} ({A})", f"أحوّط حرف {A}",
            f"Je touche toutes les lettres {a} et {A}.", f"المس كل حرف {a} و{A} في الشبكة.", 15,
            dict(target=a, grid=hunt_grid(rng, a))),
        act(lid + "-color", "color_letters", f"Je colorie les {a} en rouge et les {b} en vert", "أُلوّن الحروف",
            f"Les {a} ({A}) en rouge, les {b} ({B}) en vert.", f"لوّن حرف {A} بالأحمر وحرف {B} بالأخضر.", 15,
            dict(rules=[dict(letter=a, color="#e53935", name="rouge", ar="أحمر"), dict(letter=b, color="#43a047", name="vert", ar="أخضر")],
                 grid=hunt_grid(rng, b, 4, 4, 4))),
        act(lid + "-sound-a", "sound_pick", f"J'entoure les images qui contiennent le son {a}", f"أختار الصور التي فيها صوت {a}",
            f"Je touche les images qui contiennent le son {a}.", f"المس الصور التي تحتوي على صوت {a}.", 15, sound_pick(rng, a, known)),
        act(lid + "-sound-b", "sound_pick", f"J'entoure les images qui contiennent le son {b}", f"أختار الصور التي فيها صوت {b}",
            f"Je touche les images qui contiennent le son {b}.", f"المس الصور التي تحتوي على صوت {b}.", 15, sound_pick(rng, b, known)),
        act(lid + "-fill", "fill_letter", f"Je complète avec {a} ({A}) ou {b} ({B})", "أُكمل الحرف الناقص",
            f"Je choisis la bonne lettre : {a} ou {b}.", f"اختر الحرف الصحيح لكل فراغ: {a} أم {b}؟", 15,
            dict(choices=[a, b], items=fill_items([a, b]))),
        act(lid + "-match", "match", "Je relie", "أصل الكلمة بالصورة",
            "Je relie chaque mot à son image.", "المس الكلمة ثم المس صورتها.", 15,
            dict(pairs=[WD.card(k) for k in keys + [name_key(a), name_key(b)]])),
        act(lid + "-listen", "listen_choose", "J'écris les lettres que j'entends", "أستمع وأختار الحرف",
            "J'écoute la lettre et je la choisis.", "استمع إلى الحرف واختره من بين الحروف.", 15,
            dict(items=[dict(tts=l, answer=l, choices=letter_choices(rng, l)) for l in [a, b, a, b, a, b]])),
        act(lid + "-fun", "letter_spot", f"Je m'amuse : j'entoure la lettre {FUN_LETTER[pair]} dans les mots", f"ألعب: أجد حرف {FUN_LETTER[pair]} في الكلمات",
            f"Je touche la lettre {FUN_LETTER[pair]} dans chaque mot illustré.", f"المس حرف {FUN_LETTER[pair]} داخل كل كلمة.", 15,
            dict(letter=FUN_LETTER[pair], words=spot_words(FUN_LETTER[pair]))),
        act(lid + "-spell", "spell", "Je construis les mots", "أبني الكلمات",
            "Je mets les lettres dans l'ordre pour écrire le mot.", "رتّب الحروف لتكتب الكلمة الصحيحة.", 15,
            dict(items=[dict(WD.card(k, False), tts=WD.label(k)) for k in keys])),
        act(lid + "-memory", "memory", "Mémory", "لعبة الذاكرة",
            "Je retrouve les paires : mot et image.", "اقلب البطاقات وابحث عن كل كلمة وصورتها.", 15,
            dict(pairs=[WD.card(k) for k in keys])),
    ]
    return dict(id=lid, code=f"{A}-{B}", title=f"Les lettres {A} et {B}", title_ar=f"الحرفان {A} و{B}", icon=f"{A}{b}",
                kind="letters", extra=False, chapter=chap, activities=acts), known


def bilan_lesson(chap, title, pairs, dictation, known):
    rng = random.Random(f"u1-bilan-{chap}")
    letters = [l for p in pairs for l in p]
    all_letters = [l for c in CHAPTERS if c[0] <= chap for p in c[2] for l in p]
    lid = f"u1-bilan{chap}"
    l1, l2 = BILAN_SOUNDS[chap]
    ls, spot_list = BILAN_SPOT[chap]
    fill = fill_items(letters)
    rng.shuffle(fill)
    in_chap = [k for k in known if WD.W[k].get("letter") in letters]
    acts = [
        act(lid + "-read", "flashcards", "Je lis les lettres à voix haute", "أقرأ الحروف بصوت عالٍ",
            "J'écoute et je répète chaque lettre.", "استمع وكرّر كل حرف.", 10,
            dict(cards=[dict(kind="letter", upper=l.upper(), lower=l, tts=l, text=f"{l} {l.upper()}", ar=f"الحرف {l.upper()}") for l in all_letters])),
        act(lid + "-sound1", "sound_pick", f"J'entoure les images qui contiennent le son {l1}", f"أختار الصور التي فيها صوت {l1}",
            f"Je touche les images qui contiennent le son {l1}.", f"المس الصور التي فيها صوت {l1}.", 15, sound_pick(rng, l1, known)),
        act(lid + "-sound2", "sound_pick", f"J'entoure les images qui contiennent le son {l2}", f"أختار الصور التي فيها صوت {l2}",
            f"Je touche les images qui contiennent le son {l2}.", f"المس الصور التي فيها صوت {l2}.", 15, sound_pick(rng, l2, known)),
        act(lid + "-spot", "letter_spot", f"J'entoure la lettre {ls} dans les mots", f"أجد حرف {ls} في الكلمات",
            f"Je touche la lettre {ls} dans chaque mot.", f"المس حرف {ls} في كل كلمة.", 15,
            dict(letter=ls, words=[word_item(w) for w in spot_list])),
        act(lid + "-dictee", "listen_choose", "J'écris les lettres que j'entends", "إملاء: أستمع وأختار الحرف",
            "J'écoute et je choisis la lettre.", "استمع إلى الحرف واختره.", 20,
            dict(items=[dict(tts=l.lower(), answer=l.lower(), choices=letter_choices(rng, l.lower(), 5)) for l in dictation])),
        act(lid + "-fill", "fill_letter", "Je complète avec les lettres manquantes", "أُكمل الحروف الناقصة",
            "Je choisis la bonne lettre pour chaque trou.", "اختر الحرف الصحيح لكل فراغ.", 20,
            dict(choices=letters, items=fill[:8])),
        act(lid + "-match", "match", "Je relie", "أصل",
            "Je relie chaque mot à son image.", "المس الكلمة ثم صورتها.", 15,
            dict(pairs=[WD.card(k) for k in rng.sample(in_chap, min(8, len(in_chap)))])),
        act(lid + "-spell", "spell", "Je construis les mots", "أبني الكلمات",
            "Je mets les lettres dans l'ordre.", "رتّب الحروف لتكتب الكلمة.", 20,
            dict(items=[dict(WD.card(k, False), tts=WD.label(k)) for k in rng.sample(in_chap, min(5, len(in_chap)))])),
    ]
    return dict(id=lid, code=f"Bilan {chap}", title=f"Bilan : {title}", title_ar=f"مراجعة الفصل {chap}", icon="🏆", kind="bilan",
                extra=False, chapter=chap, activities=acts)


def song_lesson(chap):
    title, ar, lines = SONGS[chap]
    lid = f"u1-song{chap}"
    return dict(id=lid, code="Chanson", title=f"Je chante : {title}", title_ar=f"أغنية: {ar}", icon="🎵", kind="song", extra=True,
                chapter=chap, activities=[
                    act(lid + "-sing", "reading", title, ar, "J'écoute et je chante.", "استمع وغنِّ مع الأغنية.", 10,
                        dict(paragraphs=[dict(fr=l, ar="") for l in lines], emoji="🎶"))])


def build():
    lessons, known = [], []
    for chap, title, pairs, dictation in CHAPTERS:
        for pair in pairs:
            lesson, known = pair_lesson(chap, pair, known)
            lessons.append(lesson)
        lessons.append(bilan_lesson(chap, title, pairs, dictation, known))
        if chap in SONGS:
            lessons.append(song_lesson(chap))
    return dict(id="u1", title="Unité 1 : L'alphabet", title_ar="الوحدة 1: الحروف الأبجدية", color="#ff7043", icon="🔤",
                desc_ar="نتعلم الحروف من A إلى Z: نطقها وكتابتها وكلمات لكل حرف.", desc_fr="Les lettres de A à Z : les dire, les écrire et des mots pour chaque lettre.", lessons=lessons)
