#!/usr/bin/python3
"""MHMT uygulama kataloğundan kurma ve kaldırma (docs/02-mimari.md, karar #44).

  mhmt-uygulama liste [--json]
  sudo mhmt-uygulama kur [-y] [--kurucu] <öğe|grup>...
  sudo mhmt-uygulama kaldir [-y] <öğe>...

apt öğeleri apt-get ile; Flathub öğeleri mhmt-config-flatpak'ın sırasına yazılır ve
systemd çalışıyorsa hemen kurulur (kurucunun chroot'unda ilk açılışta).
"""
import json
import os
import subprocess
import sys

KATALOG = "/usr/share/mhmt/uygulamalar/katalog.json"
SIRA = "/var/lib/mhmt/flatpak/sirada"
KURULDU = "/var/lib/mhmt/flatpak/kuruldu"
FLATPAK_KUR = "/usr/libexec/mhmt-flatpak/mhmt-flatpak-kur"
APT_ENV = dict(os.environ, DEBIAN_FRONTEND="noninteractive")


def katalog():
    with open(KATALOG, encoding="utf-8") as f:
        return json.load(f)["gruplar"]


def ogeler():
    return {o["id"]: dict(o, grup=g["id"]) for g in katalog() for o in g["ogeler"]}


def apt_kurulu(paket):
    r = subprocess.run(["dpkg-query", "-W", "-f", "${Status}", paket],
                       stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, universal_newlines=True)
    return r.stdout.strip() == "install ok installed"


def satirlar(yol):
    try:
        with open(yol, encoding="utf-8") as f:
            return [s.strip() for s in f if s.strip() and not s.startswith("#")]
    except FileNotFoundError:
        return []


def flatpak_kurulu(kimlik):
    return subprocess.run(["flatpak", "info", "--system", kimlik],
                          stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0


def durum(o):
    if "apt" in o:
        return "kurulu" if all(apt_kurulu(p) for p in o["apt"]) else "kurulu değil"
    if flatpak_kurulu(o["flatpak"]):
        return "kurulu"
    return "sırada" if o["flatpak"] in satirlar(SIRA) else "kurulu değil"


def liste(args):
    gruplar = katalog()
    if "--json" in args:
        print(json.dumps({o["id"]: durum(o) for g in gruplar for o in g["ogeler"]}))
        return 0
    for g in gruplar:
        print(f"{g['ad']} ({g['id']})")
        for o in g["ogeler"]:
            kaynak = "Flathub" if "flatpak" in o else "Debian"
            print(f"  {o['id']:<15} {o['ad']:<30} {kaynak:<8} {durum(o)}")
    print("\nKurmak: sudo mhmt-uygulama kur <öğe|grup>...   Kaldırmak: sudo mhmt-uygulama kaldir <öğe>...")
    return 0


def secim(adlar):
    hepsi = ogeler()
    gruplar = {g["id"]: [o["id"] for o in g["ogeler"]] for g in katalog()}
    secilen = []
    for ad in adlar:
        if ad in gruplar:
            secilen += gruplar[ad]
        elif ad in hepsi:
            secilen.append(ad)
        else:
            sys.exit(f"mhmt-uygulama: bilinmeyen öğe ya da grup: {ad} (liste: mhmt-uygulama liste)")
    return [hepsi[i] for i in dict.fromkeys(secilen)]


def root_gerekir(komut, adlar):
    if os.geteuid() != 0:
        sys.exit(f"mhmt-uygulama: root yetkisi gerekir: sudo mhmt-uygulama {komut} {' '.join(adlar)}")


def i386_acik():
    r = subprocess.run(["dpkg", "--print-foreign-architectures"], stdout=subprocess.PIPE, universal_newlines=True)
    return "i386" in r.stdout.split()


def flatpak_sirala(kimlikler, hemen):
    os.makedirs(os.path.dirname(SIRA), exist_ok=True)
    var = satirlar(SIRA)
    with open(SIRA, "a", encoding="utf-8") as f:
        for k in kimlikler:
            if k not in var:
                f.write(k + "\n")
    # Kullanıcı açıkça istedi: daha önce kurulup kaldırılmış olsa da yeniden kurulsun.
    kuruldu = [k for k in satirlar(KURULDU) if k not in kimlikler]
    if os.path.exists(KURULDU):
        with open(KURULDU, "w", encoding="utf-8") as f:
            f.writelines(k + "\n" for k in kuruldu)
    if hemen and os.path.isdir("/run/systemd/system"):
        print("Flathub uygulamaları kuruluyor: " + " ".join(kimlikler))
        if subprocess.run([FLATPAK_KUR]).returncode != 0:
            print("mhmt-uygulama: Flathub kurulumu bitmedi, yarım saat içinde yeniden denenecek.", file=sys.stderr)
    else:
        print("Flathub uygulamaları ilk açılışta kurulacak: " + " ".join(kimlikler))


def kur(args):
    evet = "-y" in args
    kurucu = "--kurucu" in args
    adlar = [a for a in args if not a.startswith("-")]
    if not adlar:
        sys.exit("Kullanım: sudo mhmt-uygulama kur [-y] <öğe|grup>...")
    root_gerekir("kur", adlar)
    secilen = secim(adlar)
    apt_ogeleri = [o for o in secilen if "apt" in o]
    flatpaklar = [o["flatpak"] for o in secilen if "flatpak" in o]
    sonuc = 0

    if apt_ogeleri:
        paketler = [p for o in apt_ogeleri for p in o["apt"]]
        i386 = any(o.get("i386") for o in apt_ogeleri)
        acildi = False
        if i386:
            if any(o["id"] == "wine" for o in apt_ogeleri):
                paketler.append("wine32:i386")
            # Steam istemcisi 32 bit; NVIDIA kapalı sürücüde Mesa'nın i386 GL/Vulkan'ı kullanılamaz.
            if apt_kurulu("nvidia-driver-libs"):
                paketler.append("nvidia-driver-libs:i386")
            if not i386_acik():
                subprocess.run(["dpkg", "--add-architecture", "i386"], check=True)
                acildi = True
        for o in apt_ogeleri:
            for satir in o.get("debconf", []):
                subprocess.run(["debconf-set-selections"], input=satir + "\n", universal_newlines=True)
        # Eksik indeksle kurulum yarıda kalmasın: bir kaynağa ulaşılamazsa apt öğeleri kurulmaz.
        if subprocess.run(["apt-get", "update", "--error-on=any"], env=APT_ENV).returncode != 0:
            if acildi:
                subprocess.run(["dpkg", "--remove-architecture", "i386"])
            print("mhmt-uygulama: paket kaynaklarına ulaşılamadı; şunlar kurulmadı: "
                  + " ".join(o["id"] for o in apt_ogeleri)
                  + "\nSonradan: sudo mhmt-uygulama kur " + " ".join(o["id"] for o in apt_ogeleri), file=sys.stderr)
            sonuc = 1
        else:
            komut = ["apt-get", "install"] + (["-y"] if evet or kurucu else []) + paketler
            if subprocess.run(komut, env=APT_ENV).returncode != 0:
                sonuc = 1

    if flatpaklar:
        flatpak_sirala(flatpaklar, hemen=not kurucu)
    return sonuc


def kaldir(args):
    evet = "-y" in args
    adlar = [a for a in args if not a.startswith("-")]
    if not adlar:
        sys.exit("Kullanım: sudo mhmt-uygulama kaldir [-y] <öğe>...")
    root_gerekir("kaldir", adlar)
    secilen = secim(adlar)
    sonuc = 0
    paketler = [p for o in secilen if "apt" in o for p in o["apt"] if apt_kurulu(p)]
    if paketler:
        komut = ["apt-get", "purge"] + (["-y"] if evet else []) + paketler
        if subprocess.run(komut, env=APT_ENV).returncode != 0:
            sonuc = 1
        elif "--kurucu" not in args:
            # Kurucuda yapılmaz: yeni sistemde canlı imajdan kalan başka paketlere dokunmasın.
            subprocess.run(["apt-get", "autoremove", "--purge", "-y"], env=APT_ENV)
    kimlikler = [o["flatpak"] for o in secilen if "flatpak" in o]
    if kimlikler:
        sira = [k for k in satirlar(SIRA) if k not in kimlikler]
        if os.path.exists(SIRA):
            with open(SIRA, "w", encoding="utf-8") as f:
                f.writelines(k + "\n" for k in sira)
        kurulu = [k for k in kimlikler if flatpak_kurulu(k)]
        if kurulu and subprocess.run(["flatpak", "uninstall", "--system", "--noninteractive", "-y"] + kurulu).returncode != 0:
            sonuc = 1
    return sonuc


def main():
    if len(sys.argv) < 2 or sys.argv[1] in ("-h", "--help", "yardim"):
        print(__doc__.strip())
        return 0
    komutlar = {"liste": liste, "kur": kur, "kaldir": kaldir, "kaldır": kaldir}
    if sys.argv[1] not in komutlar:
        print(__doc__.strip(), file=sys.stderr)
        return 2
    return komutlar[sys.argv[1]](sys.argv[2:])


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