"""
Point d'entrée unique pour l'énumération des adresses IPv4 locales.

    adresses_locales() -> list[str]

Sélectionne le backend selon `config.OS_FAMILY` au chargement du module, comme
`wireguard_manager`, `firewall_manager` ou `hosts_file_manager` — pas de
`sys.platform` dispersé dans le code métier.

**Ce que ça sert.** Un pair n'annonçait qu'UNE adresse locale, celle de la route
par défaut. Sur une machine bi-domiciliée c'est la mauvaise : voir
`local_addresses_common` pour la mesure, et le point 90 de CLAUDE.md pour le coût
(deux machines du même commutateur transitant par un relais à 900 km).

**L'énumération ne décide de rien à elle seule.** Elle produit des CANDIDATS ;
c'est `lan_verification` qui tranche, en prouvant par une sonde que l'adresse
appartient bien au pair annoncé. Une adresse privée partagée ne prouve rien —
`192.168.0.0/24` est la plage par défaut de la quasi-totalité des box, et deux
machines à 900 km s'y trouvent toutes les deux (point 43).
"""

from __future__ import annotations

import logging

import config
import local_addresses_common

logger = logging.getLogger("meshamoto-client.local_addresses")

if config.OS_FAMILY == "windows":
    from local_addresses_backend_windows import adresses_locales  # noqa: F401
elif config.OS_FAMILY == "linux":
    from local_addresses_backend_linux import adresses_locales  # noqa: F401
else:  # pragma: no cover - aucun des deux OS supportés
    def adresses_locales() -> list[str]:
        """Repli : aucune énumération sur un OS non supporté."""
        logger.debug("Énumération des adresses locales non supportée sur %s", config.OS_FAMILY)
        return []


def adresses_locales_avec_repli(
    adresse_par_defaut: str | None, exclure_cidr: str | None = None
) -> list[str]:
    """
    Adresses énumérées, en garantissant que celle de la route par défaut y figure.

    **Le repli n'est pas une politesse, c'est la garantie de non-régression.**
    L'énumération peut échouer — `ip` absent, PowerShell bridé, délai dépassé — et
    le comportement doit alors être EXACTEMENT celui d'avant ce module : annoncer
    l'adresse de la route par défaut, découverte par socket connecté. Sans ça, une
    machine dont l'énumération échoue n'annoncerait plus aucune adresse locale et
    perdrait la préférence LAN qu'elle avait, ce qui serait une régression causée
    par une fonctionnalité censée l'améliorer.

    L'adresse par défaut est placée EN TÊTE quand elle manque : c'est la seule dont
    on sait qu'elle porte réellement du trafic.

    **`exclure_cidr` retire l'adresse du TUNNEL, et ce n'est pas cosmétique.**
    L'interface Meshamoto est une interface locale comme une autre : `ip addr` la
    liste, donc l'énumération la trouve. L'annoncer serait un défaut grave et
    silencieux — tous les pairs vivent dans la même plage virtuelle, donc cette
    adresse partagerait leur sous-réseau, deviendrait candidate chez chacun, et la
    sonde d'identité **réussirait**, l'écho répondant précisément sur l'IP virtuelle.
    WireGuard recevrait alors comme endpoint une adresse qui n'existe QUE dans le
    tunnel qu'il est censé porter. Routage circulaire, et une vérification qui
    « prouve » le mauvais chemin.

    Trouvé en confrontant l'énumération à la vraie machine, pas par un test : les
    tests d'analyse portaient sur des sorties fabriquées, où l'interface du tunnel
    n'apparaissait pas.
    """
    adresses = adresses_locales()
    if adresse_par_defaut and adresse_par_defaut not in adresses:
        adresses.insert(0, adresse_par_defaut)
    if exclure_cidr:
        adresses = [a for a in adresses if not local_addresses_common.dans_le_reseau(a, exclure_cidr)]
    return adresses
