#!/usr/bin/env python3
"""Legge dal master TWISTER v2 i testi che devono comparire in un DVR nuovo.

Per ogni punto dei Pericoli prende "Verifica e commento" (C) e "Note" (F) di
tutte le righe del blocco (un punto può occuparne più di una) e le unisce con un
a capo. Dove Uffici/Pertinenze sono viola, cioè da compilare, la cella non porta
un valore definitivo ma una scelta: in quel caso si riportano TUTTE le voci
della sua tendina, una per riga, così chi compila cancella quelle che non
servono invece di riscrivere da zero. Fa eccezione il segnaposto con la X
("L'ufficio si trova al X° piano"), dove si cambia solo la X.

Più la descrizione immobile del riquadro giallo. Non tocca il database.

    python3 import-tools/scripts/estrai_template_master.py <out.json>
"""
import json, re, sys, warnings
from pathlib import Path
warnings.filterwarnings("ignore")
import openpyxl

ROOT = Path(__file__).resolve().parents[2]
MASTER = ROOT / "-mat" / "07_DVR AGENZIE_TWISTER_v2.xlsx"
RIF = re.compile(r"^\d+(\.\d+)*$")
SEGNAPOSTO = re.compile(r"\bX\s*°")     # "L'ufficio si trova al X° piano"
norm = lambda v: re.sub(r"[ \t]+", " ", str(v)).strip() if v is not None else ""

wb = openpyxl.load_workbook(MASTER, data_only=True)
ws = wb["Pericoli"]


def tendine():
    """Voci delle tendine (data validation) delle celle C e F: {'C28': [...]}."""
    import zipfile
    z = zipfile.ZipFile(MASTER)
    xml = z.read("xl/worksheets/sheet3.xml").decode()

    def voci(rng):
        m = re.match(r"^'?([^'!]+)'?!\$?([A-Z]+)\$?(\d+):\$?([A-Z]+)\$?(\d+)$", rng.strip())
        if not m or m.group(1) not in wb.sheetnames:
            return []
        w = wb[m.group(1)]
        vals = [str(w[f"{m.group(2)}{r}"].value).strip()
                for r in range(int(m.group(3)), int(m.group(5)) + 1)
                if w[f"{m.group(2)}{r}"].value]
        # la prima voce è spesso l'elenco intero ("1_ … 2_ …") ripetuto poi voce
        # per voce: tenere entrambi darebbe doppioni, quindi si scartano gli
        # aggregati su più righe quando esistono anche le versioni singole
        singole = [v for v in vals if "\n" not in v]
        scelte = singole if singole else vals
        return [re.sub(r"[ \t]+", " ", v).strip() for v in scelte]

    out = {}
    for b in re.findall(r"<x14:dataValidation\b.*?</x14:dataValidation>", xml, re.S):
        f1 = re.search(r"<xm:f>(.*?)</xm:f>", b, re.S)
        sq = re.search(r"<xm:sqref>(.*?)</xm:sqref>", b, re.S)
        if not f1 or not sq:
            continue
        lst = voci(f1.group(1))
        if not lst:
            continue
        for part in sq.group(1).split():
            m = re.match(r"^([A-Z]+)(\d+)(?::([A-Z]+)(\d+))?$", part)
            if not m:
                continue
            c1, r1, c2, r2 = m.group(1), int(m.group(2)), m.group(3), m.group(4)
            righe = range(r1, int(r2) + 1) if c2 == c1 else [r1]
            for r in righe:
                if c1 in ("C", "F"):
                    out[f"{c1}{r}"] = lst
    return out


TENDINE = tendine()


def testo(col, riga):
    """Valore da mettere nel template per la cella <col><riga>."""
    val = norm(ws.cell(riga, 3 if col == "C" else 6).value)
    # viola = Uffici/Pertinenze da compilare: la cella è una scelta, non un valore
    viola = not norm(ws.cell(riga, 4).value) or not norm(ws.cell(riga, 5).value)
    voci = TENDINE.get(f"{col}{riga}")
    if viola and voci and not SEGNAPOSTO.search(val):
        return "\n".join(voci)
    return val

# blocchi: un punto vale fino alla riga prima del punto successivo
punti, corrente = {}, None
for r in range(2, ws.max_row + 1):
    rif = norm(ws.cell(r, 1).value)
    c, f = testo("C", r), testo("F", r)
    if rif and RIF.match(rif):
        corrente = rif if len(rif.split(".")) >= 3 else None   # solo punti veri
        if corrente:
            punti[corrente] = {"C": [c] if c else [], "F": [f] if f else []}
        continue
    if corrente and (c or f):        # riga di continuazione dello stesso punto
        if c: punti[corrente]["C"].append(c)
        if f: punti[corrente]["F"].append(f)

out = {
    "punti": {k: {"C": "\n".join(v["C"]), "F": "\n".join(v["F"])} for k, v in punti.items()},
    "descrizione": norm(wb["Dati"]["A30"].value),
}
json.dump(out, open(sys.argv[1], "w"), ensure_ascii=False, indent=1)
multi = sum(1 for v in punti.values() if len(v["C"]) > 1 or len(v["F"]) > 1)
print(f"punti letti: {len(punti)} (di cui su più righe: {multi})")
print(f"descrizione: {len(out['descrizione'])} caratteri")
