"""
Avis de licence des composants tiers, affiché par « À propos ».

**Ce n'est pas de la politesse : la LGPLv3 exige un avis VISIBLE.** Meshamoto est
propriétaire mais embarque Qt via PySide6 sous LGPLv3, ce qui impose de signaler que
la bibliothèque est utilisée, de fournir le texte des licences, et de laisser
l'utilisateur la remplacer. Le fichier `NOTICE.md` porte le détail ; ce module le
trouve, quel que soit le format d'installation.

**L'AVIS ESSENTIEL EST DANS LE CODE, pas seulement dans le fichier.** Un `NOTICE.md`
absent — empaquetage bâclé, fichier supprimé — ne doit pas faire disparaître
l'obligation avec lui. `AVIS_MINIMAL` est donc affiché dans tous les cas, et le
fichier vient s'y ajouter quand on le trouve.

Logique pure : les chemins sont passés en paramètre, rien n'est lu à l'import.
"""

from __future__ import annotations

import sys
from pathlib import Path

NOM_FICHIER = "NOTICE.md"

# Toujours affiché, même sans NOTICE.md. Contient les trois éléments que la LGPL
# réclame : que la bibliothèque est utilisée, sous quelle licence, et comment la
# remplacer. Plus l'attribution de marque de WireGuard.
AVIS_MINIMAL = """Meshamoto est un logiciel propriétaire. © 2026, tous droits réservés.

Il utilise **Qt**, via **PySide6**, sous licence **GNU LGPL version 3**.

Vous avez le droit de remplacer les bibliothèques Qt et PySide6 fournies avec
Meshamoto par une version modifiée. Elles sont livrées sous forme de fichiers
distincts, à côté de l'exécutable, précisément pour que cela reste possible.
Sur Arch et CachyOS, rien n'est fourni du tout : le paquet dépend du `pyside6` du
système, que vous remplacez avec `pacman`.

Sources de Qt : https://download.qt.io/official_releases/qt/

Meshamoto invoque **WireGuard** comme programme séparé et ne l'embarque pas.
WireGuard est une marque déposée de Jason A. Donenfeld ; Meshamoto n'est ni affilié
à, ni approuvé par, le projet WireGuard."""


def emplacements_possibles(
    fige: bool, executable: str, module: str, prefixe_appimage: str | None = None
) -> list[Path]:
    """
    Où chercher `NOTICE.md`, du plus spécifique au plus général.

    Quatre formats de distribution, quatre emplacements — et le défaut « à côté du
    module » ne convient à aucun d'eux une fois empaqueté. Même famille de piège que
    la base SQLite du point 45 et le canal du relais du point 86, d'où le passage des
    paramètres plutôt qu'une lecture directe de `sys` : le cas figé est précisément
    celui qu'on ne peut pas exercer depuis la suite de tests.
    """
    chemins: list[Path] = []
    if fige:
        # --onedir : `licenses/` est à côté de l'exécutable réel.
        chemins.append(Path(executable).resolve().parent / "licenses")
    if prefixe_appimage:
        chemins.append(Path(prefixe_appimage) / "usr" / "share" / "licenses" / "meshamoto")
    # Paquet Arch.
    chemins.append(Path("/usr/share/licenses/meshamoto"))
    # Exécution depuis les sources : client/ -> racine du dépôt.
    chemins.append(Path(module).resolve().parent.parent / "packaging" / "licenses")
    return chemins


def trouver_notice(emplacements: list[Path]) -> Path | None:
    for dossier in emplacements:
        candidat = dossier / NOM_FICHIER
        try:
            if candidat.is_file():
                return candidat
        except OSError:
            continue
    return None


def texte_a_afficher(notice: Path | None) -> str:
    """
    Le fichier de notices s'il est lisible, l'avis minimal sinon.

    **L'obligation ne dépend jamais de la présence du fichier** : c'est tout l'objet
    d'`AVIS_MINIMAL`, codé en dur, et le repli reste inchangé. Une contrainte
    juridique ne doit pas disparaître avec un empaquetage raté.

    Mais on ne CONCATÈNE plus les deux, contrairement au premier jet. `NOTICE.md` est
    un sur-ensemble strict de l'avis minimal — mêmes obligations, en plus détaillé —
    donc les enchaîner faisait lire deux fois Qt/LGPL, le droit de remplacement et la
    marque WireGuard. Signalé le 2026-08-07 en regardant l'écran : trois écrans de
    défilement dont la première moitié répétait la seconde, ce qui dessert
    précisément l'avis qu'on veut rendre visible.
    Le sur-ensemble n'est pas une espérance : un test vérifie que `NOTICE.md` porte
    chacune des obligations d'`AVIS_MINIMAL`, et tombe si quelqu'un l'allège.
    """
    if notice is None:
        return AVIS_MINIMAL + "\n\n_(Le détail des autres composants est absent de " \
            "cette installation.)_"
    try:
        return notice.read_text(encoding="utf-8")
    except OSError:
        return AVIS_MINIMAL


def avis_complet() -> str:
    """Point d'entrée de la GUI : résout les chemins réels puis rend le texte."""
    return texte_a_afficher(
        trouver_notice(
            emplacements_possibles(
                getattr(sys, "frozen", False),
                sys.executable,
                __file__,
                _prefixe_appimage(),
            )
        )
    )


def _prefixe_appimage() -> str | None:
    import os

    # `APPDIR` est posée par le runtime AppImage. `sys.executable` ne dirait rien :
    # il pointe dans le montage temporaire (même raisonnement qu'au point 58).
    return os.environ.get("APPDIR")
