#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Nom du script  : prepare_svg_analyses.py
Chemin         : /var/www/html/analyses/prepare_svg_analyses.py

Description :
    Nettoie un SVG exporté depuis QGIS pour le projet "analyses" et le rend
    exploitable côté web.

    Fonctionnalités :
      - Charge un SVG brut (export QGIS).
      - Supprime tous les <rect> (fonds / cadres QGIS).
      - Supprime les styles inline (style, fill, stroke, etc.).
      - Ajoute id="carte-analyses" à la balise <svg>.
      - Renomme les groupes de couches :
            * "Carte 1: zones"  -> id="zones"
            * "Carte 1: sites"  -> id="sites"
            * "Carte 1: galicia-..." -> ajout class="terre"
      - Attribue des IDs séquentiels aux géométries :
            * zones :  zone-1, zone-2, ...
            * sites :  site-1, site-2, ...
        (dans l'ordre des <path>/<polygon> dans le SVG)
      - Écrit un SVG final propre.

Options :
    Modifier les constantes SVG_INPUT / SVG_OUTPUT si nécessaire.

Exemple d'utilisation :
    cd /var/www/html/analyses
    python3 prepare_svg_analyses.py

Prérequis :
    - Python 3
    - lxml (sudo apt-get install python3-lxml)

Auteur      : Sylvain SCATTOLINI
Date        : 2025-11-27
Version     : 1.1
"""

import sys
from typing import List

from lxml import etree


# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------

SVG_INPUT = "carte_analyses_qgis.svg"     # SVG exporté depuis QGIS
SVG_OUTPUT = "carte_analyses_final.svg"   # SVG nettoyé pour le site

# Fragments utilisés pour reconnaître les groupes dans le SVG QGIS
LAYER_ZONES_NAME = "Carte 1: zones"
LAYER_SITES_NAME = "Carte 1: sites"
LAYER_GALICE_PATTERN = "Carte 1: galicia-"

# Namespaces SVG
NS = {
    "svg": "http://www.w3.org/2000/svg",
    "serif": "http://www.serif.com/",
}


# ---------------------------------------------------------------------------
# Fonctions utilitaires
# ---------------------------------------------------------------------------

def remove_rectangles(root: etree._Element) -> None:
    """Supprime tous les <rect> du SVG (fonds, cadres, etc.)."""
    rects = root.findall(".//svg:rect", namespaces=NS)
    print(f"[INFO] Rectangles trouvés : {len(rects)} (ils seront supprimés)")
    for r in rects:
        parent = r.getparent()
        if parent is not None:
            parent.remove(r)


def remove_inline_styles(root: etree._Element) -> None:
    """Supprime les styles inline pour laisser la main au CSS externe."""
    count = 0
    for elem in root.xpath(".//*"):
        modified = False
        for attr in [
            "style",
            "fill",
            "stroke",
            "stroke-width",
            "opacity",
            "fill-opacity",
            "stroke-linecap",
            "stroke-linejoin",
        ]:
            if attr in elem.attrib:
                del elem.attrib[attr]
                modified = True
        if modified:
            count += 1
    print(f"[INFO] Éléments nettoyés de styles inline : {count}")


def ensure_svg_id(root: etree._Element, svg_id: str = "carte-analyses") -> None:
    """Force un id sur la balise <svg> racine."""
    if not root.tag.endswith("svg"):
        print("[AVERTISSEMENT] Élément racine différent de <svg> ?", file=sys.stderr)
    root.attrib["id"] = svg_id
    print(f"[INFO] id du <svg> défini sur '{svg_id}'")


def rename_layer_group(root: etree._Element, layer_name: str, new_id: str) -> int:
    """
    Renomme les groupes correspondant à une couche QGIS en leur donnant id=new_id.

    On se base sur l'attribut id ou serif:id (export QGIS, Affinity, etc.).
    """
    renamed = 0
    for g in root.findall(".//svg:g", namespaces=NS):
        gid = g.attrib.get("id", "")
        serif_id = g.attrib.get(f"{{{NS['serif']}}}id", "")
        if gid == layer_name or serif_id == layer_name:
            g.attrib["id"] = new_id
            renamed += 1
    print(f"[INFO] Groupes '{layer_name}' renommés en id='{new_id}' : {renamed}")
    return renamed


def mark_galice_as_terre(root: etree._Element, pattern: str) -> int:
    """
    Ajoute class='terre' au groupe correspondant à la couche Galice (terre).
    On cherche pattern dans id ou serif:id.
    """
    marked = 0
    for g in root.findall(".//svg:g", namespaces=NS):
        gid = g.attrib.get("id", "")
        serif_id = g.attrib.get(f"{{{NS['serif']}}}id", "")
        if pattern in gid or pattern in serif_id:
            existing_class = g.attrib.get("class", "")
            classes = (existing_class + " terre").strip()
            g.attrib["class"] = classes
            marked += 1
    print(f"[INFO] Groupes Galice marqués class='terre' : {marked}")
    return marked


def assign_ids_to_group_paths(root: etree._Element, group_id: str, prefix: str) -> int:
    """
    Attribue des ids séquentiels aux géométries (<path>, <polygon>, <polyline>)
    d'un groupe donné : prefix-1, prefix-2, ...

    Exemple :
        group_id='zones', prefix='zone' -> zone-1, zone-2, ...
    """
    groups = root.findall(f".//svg:g[@id='{group_id}']", namespaces=NS)
    if not groups:
        print(f"[AVERTISSEMENT] Aucun groupe avec id='{group_id}' trouvé.")
        return 0

    assigned = 0
    for g in groups:
        # On prend les éléments géométriques usuels
        elems = []
        elems.extend(g.findall(".//svg:path", namespaces=NS))
        elems.extend(g.findall(".//svg:polygon", namespaces=NS))
        elems.extend(g.findall(".//svg:polyline", namespaces=NS))

        print(f"[INFO] Groupe '{group_id}' : {len(elems)} géométrie(s) à numéroter")

        for elem in elems:
            assigned += 1
            elem.attrib["id"] = f"{prefix}-{assigned}"

    print(f"[INFO] IDs assignés pour '{group_id}' avec préfixe '{prefix}-' : {assigned}")
    return assigned


# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------

def main() -> int:
    print("=== Préparation du SVG 'analyses' ===")
    print(f"[INFO] Lecture : {SVG_INPUT}")

    try:
        parser = etree.XMLParser(remove_comments=True)
        tree = etree.parse(SVG_INPUT, parser)
        root = tree.getroot()
    except OSError as exc:
        print(f"[ERREUR] Impossible de lire le SVG d'entrée : {exc}", file=sys.stderr)
        return 1
    except etree.XMLSyntaxError as exc:
        print(f"[ERREUR] SVG mal formé : {exc}", file=sys.stderr)
        return 1

    # Nettoyage de base
    remove_rectangles(root)
    remove_inline_styles(root)
    ensure_svg_id(root, "carte-analyses")

    # Normalisation des groupes
    rename_layer_group(root, LAYER_ZONES_NAME, "zones")
    rename_layer_group(root, LAYER_SITES_NAME, "sites")
    mark_galice_as_terre(root, LAYER_GALICE_PATTERN)

    # Attribution d'IDs séquentiels
    nb_zones = assign_ids_to_group_paths(root, "zones", "zone")
    nb_sites = assign_ids_to_group_paths(root, "sites", "site")

    print(f"[INFO] Zones numérotées : {nb_zones}")
    print(f"[INFO] Sites numérotés : {nb_sites}")

    # Écriture du SVG final
    try:
        tree.write(SVG_OUTPUT, encoding="utf-8", pretty_print=True, xml_declaration=True)
    except OSError as exc:
        print(f"[ERREUR] Impossible d'écrire le SVG de sortie : {exc}", file=sys.stderr)
        return 1

    print(f"[SUCCÈS] SVG final écrit dans : {SVG_OUTPUT}")
    print("=== Terminé ===")
    return 0


if __name__ == "__main__":
    sys.exit(main())