# -*- coding: utf-8 -*-
"""
Synchronise table, siège et remarques depuis mariage.csv vers les fiches guests.
Réécrit les remarques du CSV (version polie).
"""
from __future__ import annotations

import csv
import re
import unicodedata
from collections import defaultdict
from io import StringIO
from pathlib import Path

ROOT = Path(__file__).resolve().parent.parent
CSV_PATH = ROOT / "mariage.csv"
CSV_FALLBACK_PATH = Path(r"c:\Users\yanni\OneDrive\mariage.csv")
GUESTS_DIR = ROOT / "content" / "collections" / "guests"


def resolve_csv_path() -> Path:
    if CSV_PATH.exists():
        return CSV_PATH
    if CSV_FALLBACK_PATH.exists():
        return CSV_FALLBACK_PATH
    raise FileNotFoundError("CSV introuvable (repo et OneDrive)")


def table_prefix(table_name: str) -> str:
    n = (table_name or "").strip()
    if not n or n.upper() in ("#N/A", "N/A"):
        return "X"
    for ch in n:
        if ch.isalpha():
            base = unicodedata.normalize("NFD", ch)[0]
            return base.upper()
    return "X"


def polish_remark(raw: str) -> str:
    if not raw or not str(raw).strip():
        return ""
    s = re.sub(r"\s+", " ", str(raw).strip().replace("\n", " "))
    low = s.lower()

    if "allergie" in low and "ananas" in low:
        return "Une personne est allergique à l’ananas."
    if "rachel" in low and "ven" in low:
        return "Rachel ne pourra malheureusement pas être des nôtres."
    if "coriandre" in low and "poisson" in low:
        return (
            "Alex : merci de prévoir sans coriandre. "
            "Gaël : merci de prévoir sans poisson ni fruits de mer."
        )
    if s == "Allergie aux poivrons" or low == "allergie aux poivrons":
        return "Allergie aux poivrons."
    if re.match(r"^2\s*x\s*végé", low) or re.match(r"^2\s*x\s*veg", low):
        return "Deux convives au régime végétarien."
    if re.match(r"^1\s*x\s*végé", low) or re.match(r"^1x\s*végé", low):
        return "Un convive au régime végétarien."
    if "musulman" in low and "porc" in low:
        return "Pas de porc (convives de confession musulmane)."
    if "lactose" in low and "flatul" in low:
        return (
            "Sans lactose ; merci d’éviter les légumes susceptibles de provoquer "
            "des inconforts digestifs."
        )
    if "mangue" in low or "mangues" in low:
        if "celer" in low or "céler" in low:
            return "Allergie à la mangue et au céleri."

    if not s.endswith((".", "!", "?", "…")):
        s = s + "."
    return s


def parse_csv_rows() -> list[dict]:
    csv_path = resolve_csv_path()
    text = csv_path.read_text(encoding="utf-8-sig")
    reader = csv.reader(StringIO(text), delimiter=";")
    header = next(reader)
    idx = {name: header.index(name) for name in header}
    rows = []
    for row in reader:
        while len(row) < len(header):
            row.append("")
        rows.append(
            {
                "name": row[idx["Liste de nom"]].strip(),
                "code1": row[idx["Code"]].strip(),
                "code2": row[idx["Code 2"]].strip() if "Code 2" in idx else "",
                "table_name": row[idx["Table name"]].strip(),
                "remarks": row[idx["Remarques"]].strip(),
                "category": row[idx["Cat"]].strip() if "Cat" in idx else "",
                "side": row[idx["Lien"]].strip() if "Lien" in idx else "",
            }
        )
    return rows


def build_assignments(rows: list[dict]) -> dict[str, dict]:
    seat_counter: dict[str, int] = defaultdict(int)
    code_to: dict[str, dict] = {}

    for row in rows:
        if not row["name"] or row["name"].startswith("#"):
            continue
        codes = [c for c in (row["code1"], row["code2"]) if c]
        if not codes:
            continue
        tbl = row["table_name"] or ""
        rem = polish_remark(row["remarks"])
        prefix = table_prefix(tbl)
        for c in codes:
            seat_counter[tbl] += 1
            seat = f"{prefix}{seat_counter[tbl]}"
            code_to[c] = {
                "table": tbl,
                "seat": seat,
                "remarks": rem,
                "guest_category": row["category"],
                "guest_side": row["side"],
            }
    return code_to


def strip_generated_fields(fm_lines: list[str]) -> list[str]:
    """Retire les champs générés (y compris remarks en bloc |)."""
    out: list[str] = []
    i = 0
    while i < len(fm_lines):
        line = fm_lines[i]
        st = line.lstrip()
        if (
            st.startswith("table:")
            or st.startswith("seat:")
            or st.startswith("guest_category:")
            or st.startswith("guest_side:")
        ):
            i += 1
            continue
        if st.startswith("remarks:"):
            if st.rstrip().endswith("|"):
                i += 1
                while i < len(fm_lines) and (
                    fm_lines[i].startswith("  ") or fm_lines[i].strip() == ""
                ):
                    i += 1
            else:
                i += 1
            continue
        out.append(line)
        i += 1
    return out


def fm_lines_for_generated_fields(
    table: str,
    seat: str,
    remarks: str,
    guest_category: str,
    guest_side: str,
) -> list[str]:
    lines: list[str] = []
    lines.append(f'table: "{table}"\n' if table else "table: ''\n")
    lines.append(f'seat: "{seat}"\n' if seat else "seat: ''\n")
    lines.append(
        f'guest_category: "{guest_category}"\n' if guest_category else "guest_category: ''\n"
    )
    lines.append(f'guest_side: "{guest_side}"\n' if guest_side else "guest_side: ''\n")
    if remarks:
        lines.append("remarks: |\n")
        for pl in remarks.split("\n"):
            lines.append(f"  {pl}\n")
    else:
        lines.append("remarks: ''\n")
    return lines


def inject_after_short_name(fm_lines: list[str], extra: list[str]) -> list[str]:
    out: list[str] = []
    inserted = False
    for line in fm_lines:
        out.append(line)
        if not inserted and line.lstrip().startswith("short_name:"):
            out.extend(extra)
            inserted = True
    if not inserted:
        out = extra + out
    return out


def sync_one_file(path: Path, u: dict) -> None:
    text = path.read_text(encoding="utf-8")
    if not text.startswith("---"):
        return
    parts = text.split("---", 2)
    if len(parts) < 3:
        return
    fm_raw = parts[1]
    body = parts[2]
    fm_lines = fm_raw.splitlines(keepends=True)
    fm_lines = strip_generated_fields(fm_lines)
    extra = fm_lines_for_generated_fields(
        u["table"],
        u["seat"],
        u["remarks"],
        u["guest_category"],
        u["guest_side"],
    )
    fm_lines = inject_after_short_name(fm_lines, extra)
    new_text = "---" + "".join(fm_lines) + "---" + body
    path.write_text(new_text, encoding="utf-8")


def sync_guest_files(code_to: dict[str, dict]) -> None:
    for p in GUESTS_DIR.glob("*.md"):
        text = p.read_text(encoding="utf-8")
        if "---" not in text:
            continue
        fm = text.split("---", 2)[1]
        code = None
        for line in fm.splitlines():
            if line.strip().startswith("code:"):
                code = line.split(":", 1)[1].strip().strip("'\"")
                break
        if not code or code not in code_to:
            continue
        sync_one_file(p, code_to[code])


def write_csv_polished() -> None:
    csv_path = resolve_csv_path()
    text = csv_path.read_text(encoding="utf-8-sig")
    reader = csv.reader(StringIO(text), delimiter=";")
    header = next(reader)
    idx_r = header.index("Remarques")
    rows_out = [header]
    for row in reader:
        while len(row) < len(header):
            row.append("")
        row[idx_r] = polish_remark(row[idx_r])
        rows_out.append(row)
    try:
        with csv_path.open("w", encoding="utf-8-sig", newline="") as f:
            w = csv.writer(f, delimiter=";")
            w.writerows(rows_out)
    except PermissionError:
        print(f"CSV verrouillé, écriture ignorée: {csv_path}")


def main():
    csv_path = resolve_csv_path()
    rows = parse_csv_rows()
    code_to = build_assignments(rows)
    print(f"Codes mappés: {len(code_to)}")
    sync_guest_files(code_to)
    write_csv_polished()
    print("OK —", csv_path)


if __name__ == "__main__":
    main()
