"""
Logique pure (indépendante de l'OS) pour le DNS interne : résoudre les pairs par nom
(ex: `alice.meshamoto`) plutôt que par IP virtuelle `25.x.x.x`, via un bloc délimité
dans le fichier hosts système (`/etc/hosts` sur Linux, `System32\\drivers\\etc\\hosts`
sur Windows). Aucune I/O ni élévation de privilèges ici — voir hosts_file_manager.py
et les backends pour la partie OS-spécifique (là où le fichier est réellement écrit).

Sécurité : `display_name` provient d'un autre pair via le serveur de signalisation,
donc d'une source pas totalement fiable. Sans nettoyage, un pseudo malveillant
contenant un saut de ligne pourrait injecter des lignes arbitraires dans le fichier
hosts d'un autre utilisateur (ex: rediriger un domaine légitime vers une IP contrôlée
par l'attaquant). `_sanitize_label` élimine tout caractère hors `[a-z0-9-]`, ce qui
élimine par construction les sauts de ligne et espaces.
"""

from __future__ import annotations

import re

HOSTS_BLOCK_BEGIN = "# BEGIN MESHAMOTO"
HOSTS_BLOCK_END = "# END MESHAMOTO"
DOMAIN_SUFFIX = "meshamoto"

_INVALID_LABEL_CHARS = re.compile(r"[^a-z0-9-]+")
_FALLBACK_LABEL = "peer"


def _sanitize_label(display_name: str) -> str:
    """Réduit un display_name arbitraire à un label DNS sûr : minuscules, uniquement
    [a-z0-9-], sans espace ni saut de ligne. Retombe sur "peer" si le résultat est vide
    (ex: un pseudo entièrement composé d'emojis ou de caractères non-ASCII)."""
    label = _INVALID_LABEL_CHARS.sub("-", display_name.lower()).strip("-")
    return label or _FALLBACK_LABEL


def build_hostnames(name_to_ip: dict[str, str]) -> dict[str, str]:
    """
    Convertit {display_name: virtual_ip} en {hostname_qualifié: virtual_ip}, en
    désambiguïsant les collisions de labels (ex: deux pairs nommés "Alice!" et
    "alice") en suffixant avec les derniers octets de l'IP virtuelle.
    """
    labels_seen: dict[str, int] = {}
    result: dict[str, str] = {}
    for display_name, virtual_ip in name_to_ip.items():
        label = _sanitize_label(display_name)
        if label in labels_seen:
            labels_seen[label] += 1
            ip_suffix = virtual_ip.replace(".", "-")
            label = f"{label}-{ip_suffix}"
        else:
            labels_seen[label] = 1
        result[f"{label}.{DOMAIN_SUFFIX}"] = virtual_ip
    return result


def _strip_existing_block(existing_content: str) -> str:
    """Retire le bloc Meshamoto délimité s'il existe déjà (mise à jour idempotente),
    laisse le reste du fichier hosts strictement inchangé."""
    lines = existing_content.splitlines()
    result_lines: list[str] = []
    inside_block = False
    for line in lines:
        stripped = line.strip()
        if stripped == HOSTS_BLOCK_BEGIN:
            inside_block = True
            continue
        if stripped == HOSTS_BLOCK_END:
            inside_block = False
            continue
        if not inside_block:
            result_lines.append(line)
    return "\n".join(result_lines)


def build_updated_hosts_content(existing_content: str, name_to_ip: dict[str, str]) -> str:
    """Remplace (ou insère) le bloc Meshamoto dans le contenu du fichier hosts."""
    base = _strip_existing_block(existing_content).rstrip("\n")
    hostnames = build_hostnames(name_to_ip)
    if not hostnames:
        return base + "\n" if base else ""

    block_lines = [HOSTS_BLOCK_BEGIN]
    for hostname, virtual_ip in sorted(hostnames.items()):
        block_lines.append(f"{virtual_ip}\t{hostname}")
    block_lines.append(HOSTS_BLOCK_END)

    parts = [base] if base else []
    parts.append("\n".join(block_lines))
    return "\n".join(parts) + "\n"


def build_cleared_hosts_content(existing_content: str) -> str:
    """Retire le bloc Meshamoto, laisse tout le reste du fichier hosts inchangé."""
    base = _strip_existing_block(existing_content).rstrip("\n")
    return base + "\n" if base else ""
