"""Network Shares — Remote-Bookmarks für den Dateimanager (Nautilus). UI-frei.

Verwaltet Remote-Verbindungen (SFTP/FTP/SMB/WebDAV/NFS) als GTK-3-Bookmarks
in `~/.config/gtk-3.0/bookmarks` plus `gio mount` zum Verbinden. Alles
User-Level: GVfs läuft im Session-Bus, kein root. Lokale `file://`-Bookmarks
werden NIE angefasst — nur Remote-Zeilen (scheme in REMOTE_SCHEMES).

SMB/NFS brauchen die GVfs-Backends `gvfs-smb`/`gvfs-nfs` (eigene Pakete).
"""
from __future__ import annotations

import os
import subprocess
from dataclasses import dataclass

REMOTE_SCHEMES = {"sftp", "ftp", "smb", "dav", "davs", "nfs"}


def _config_home() -> str:
    return os.environ.get("XDG_CONFIG_HOME") or os.path.expanduser("~/.config")


def bookmarks_path() -> str:
    return os.path.join(_config_home(), "gtk-3.0", "bookmarks")


@dataclass
class Bookmark:
    uri: str
    label: str
    scheme: str


def _scheme(uri: str) -> str:
    return uri.split("://", 1)[0].lower() if "://" in uri else ""


def _read_lines() -> list[str]:
    try:
        with open(bookmarks_path(), encoding="utf-8") as fh:
            return [ln.rstrip("\n") for ln in fh]
    except OSError:
        return []


def list_remote() -> list[Bookmark]:
    """Alle Remote-Bookmarks (scheme in REMOTE_SCHEMES). file:// bleibt außen vor."""
    out: list[Bookmark] = []
    for line in _read_lines():
        line = line.strip()
        if not line:
            continue
        parts = line.split(maxsplit=1)
        uri = parts[0]
        label = parts[1] if len(parts) > 1 else uri
        sch = _scheme(uri)
        if sch in REMOTE_SCHEMES:
            out.append(Bookmark(uri=uri, label=label, scheme=sch))
    return out


def build_uri(scheme: str, host: str, path: str = "",
              user: str = "", port: str = "") -> str:
    """Baut eine GVfs-URI, z. B. `sftp://user@host:2222/srv`.

    user/port optional. path wird mit führendem „/" normalisiert.
    SMB-Konvention: `smb://host/share` (share = path ohne führenden Slash-Zwang,
    wird aber ebenfalls über den Slash drangehängt).
    """
    scheme = scheme.strip().lower()
    host = host.strip()
    user = user.strip()
    port = port.strip()
    path = path.strip()

    authority = host
    if user:
        authority = f"{user}@{authority}"
    if port:
        authority = f"{authority}:{port}"

    uri = f"{scheme}://{authority}"
    if path:
        if not path.startswith("/"):
            path = "/" + path
        uri += path
    return uri


def add_bookmark(uri: str, label: str) -> None:
    """Remote-Bookmark hinzufügen (idempotent). Alle anderen Zeilen — inkl.
    lokaler file://-Bookmarks — bleiben unverändert erhalten."""
    uri = uri.strip()
    if not uri:
        return
    lines = _read_lines()
    # Vorhandenen Eintrag mit derselben URI entfernen (Duplikate vermeiden).
    kept = [ln for ln in lines if ln.strip().split(maxsplit=1)[:1] != [uri]]
    entry = uri if not label.strip() else f"{uri} {label.strip()}"
    kept.append(entry)
    _write_lines(kept)


def remove_bookmark(uri: str) -> None:
    """Entfernt genau die Bookmark-Zeile(n) mit dieser URI. Alles andere bleibt."""
    uri = uri.strip()
    lines = _read_lines()
    kept = [ln for ln in lines if ln.strip().split(maxsplit=1)[:1] != [uri]]
    _write_lines(kept)


def _write_lines(lines: list[str]) -> None:
    path = bookmarks_path()
    os.makedirs(os.path.dirname(path), exist_ok=True)
    # Leere Zeilen am Ende vermeiden, genau ein abschließendes Newline.
    body = "\n".join(ln for ln in lines if ln.strip() != "")
    with open(path, "w", encoding="utf-8") as fh:
        fh.write(body + ("\n" if body else ""))


def mount_argv(uri: str) -> list[str]:
    return ["gio", "mount", uri]


def unmount_argv(uri: str) -> list[str]:
    return ["gio", "mount", "-u", uri]


def _pkg_installed(name: str) -> bool:
    """True, wenn das Pacman-Paket installiert ist (rc 0). GVfs-Backends sind
    Libs ohne eigenes Binary, deshalb Paketabfrage statt shutil.which."""
    try:
        r = subprocess.run(["pacman", "-Q", name], capture_output=True,
                           text=True, timeout=6, check=False)
        return r.returncode == 0
    except (OSError, subprocess.SubprocessError):
        return False


def smb_available() -> bool:
    return _pkg_installed("gvfs-smb")


def nfs_available() -> bool:
    return _pkg_installed("gvfs-nfs")


def install_smb_argv() -> list[str]:
    return ["pacman", "-S", "--needed", "--noconfirm", "gvfs-smb"]


def install_nfs_argv() -> list[str]:
    return ["pacman", "-S", "--needed", "--noconfirm", "gvfs-nfs"]
