"""
docx_lib — lecteur .docx minimal, sans dépendance externe (stdlib uniquement).

Un fichier .docx est une archive zip ; le texte vit dans word/document.xml
(format WordprocessingML). Ce module ne fait AUCUNE hypothèse propre à equirs :
il transforme un .docx en une liste de "blocs" génériques (titres, paragraphes,
tableaux) que n'importe quel parseur de projet peut ensuite interpréter.
Réutilisable tel quel pour l'ingestion d'un futur projet dans l'outil multi-projets.
"""

import zipfile
import xml.etree.ElementTree as ET

W_NS = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
NS = {"w": W_NS}


def _tag(name):
    return f"{{{W_NS}}}{name}"


def _paragraph_text(p):
    """Concatène le texte de tous les runs (w:r/w:t) d'un paragraphe.
    Un saut de ligne interne (w:br) devient un '\\n'."""
    parts = []
    for node in p.iter():
        if node.tag == _tag("t"):
            parts.append(node.text or "")
        elif node.tag == _tag("br"):
            parts.append("\n")
        elif node.tag == _tag("tab"):
            parts.append("\t")
    return "".join(parts)


def _paragraph_style(p):
    pPr = p.find(_tag("pPr"))
    if pPr is None:
        return None
    style = pPr.find(_tag("pStyle"))
    if style is None:
        return None
    return style.get(_tag("val"))


def _cell_text(tc):
    """Texte d'une cellule de tableau = ses paragraphes joints par \\n."""
    lines = []
    for p in tc.findall(_tag("p")):
        text = _paragraph_text(p)
        if text.strip():
            lines.append(text)
    return "\n".join(lines).strip()


def _parse_table(tbl):
    rows = []
    for tr in tbl.findall(_tag("tr")):
        cells = [_cell_text(tc) for tc in tr.findall(_tag("tc"))]
        rows.append(cells)
    return rows


HEADING_STYLES = {
    "Heading1": "h1",
    "Heading2": "h2",
    "Heading3": "h3",
    "Title": "h1",
}


def read_blocks(path):
    """Retourne une liste de blocs dans l'ordre du document :
    {"type": "h1"|"h2"|"h3"|"p", "text": str}
    {"type": "table", "rows": [[cell, ...], ...]}
    Les paragraphes vides (sauts de page, etc.) sont ignorés.
    """
    with zipfile.ZipFile(path) as z:
        xml_bytes = z.read("word/document.xml")
    root = ET.fromstring(xml_bytes)
    body = root.find(_tag("body"))
    blocks = []
    for child in body:
        if child.tag == _tag("p"):
            text = _paragraph_text(child)
            if not text.strip():
                continue
            style = _paragraph_style(child)
            block_type = HEADING_STYLES.get(style, "p")
            blocks.append({"type": block_type, "text": text.strip()})
        elif child.tag == _tag("tbl"):
            rows = _parse_table(child)
            blocks.append({"type": "table", "rows": rows})
        # autres éléments (sectPr, etc.) ignorés
    return blocks


def key_value_table(rows):
    """Convertit un tableau à 2 colonnes en dict {label: valeur}."""
    d = {}
    for row in rows:
        if len(row) >= 2 and row[0].strip():
            d[row[0].strip()] = row[1].strip()
    return d
