#!/usr/bin/env python3
import os
import sys
import json
import shutil
import subprocess
from pathlib import Path
from datetime import datetime

VERSION = "1.0.1"
CONFIRM_APPLY = "APPLY_SENTINELOS_LOGIN_SCREEN"
CONFIRM_RESTORE = "RESTORE_SENTINELOS_LOGIN_SCREEN"

POLICY = Path("/usr/share/sentinelos/login-screen/policy.json")
BG = Path("/usr/share/backgrounds/sentinelos/sentinelos-login-dark-cyan.svg")
BRAND = Path("/usr/share/sentinelos/login-screen/sentinelos-login-brand.svg")
STATE = Path("/var/lib/sentinelos/login-screen")
BACKUPS = STATE / "backups"
ACTIVE = STATE / "active_restore.json"

GTK_CONF = Path("/etc/lightdm/lightdm-gtk-greeter.conf.d/60-sentinelos-login.conf")
SLICK_CONF = Path("/etc/lightdm/slick-greeter.conf.d/60-sentinelos-login.conf")

GTK_TEXT = f"""[greeter]
background={BG}
theme-name=SentinelOS-Dark-Cyan
icon-theme-name=SentinelOS-Light
font-name=Sans 11
xft-antialias=true
xft-hintstyle=hintslight
user-background=false
indicators=~host;~spacer;~clock;~spacer;~session;~language;~a11y;~power
"""

SLICK_TEXT = f"""[Greeter]
background={BG}
theme-name=SentinelOS-Dark-Cyan
icon-theme-name=SentinelOS-Light
draw-user-backgrounds=false
show-hostname=true
"""

def dpkg_installed(pkg):
    try:
        p = subprocess.run(["dpkg-query", "-W", "-f=${Status}", pkg], text=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, timeout=10)
        return p.returncode == 0 and "install ok installed" in p.stdout
    except Exception:
        return False

def lightdm_present():
    return Path("/etc/lightdm").exists() or dpkg_installed("lightdm")

def gtk_greeter_present():
    return Path("/etc/lightdm/lightdm-gtk-greeter.conf.d").exists() or Path("/usr/sbin/lightdm-gtk-greeter").exists() or dpkg_installed("lightdm-gtk-greeter")

def slick_present():
    return Path("/etc/lightdm/slick-greeter.conf.d").exists() or Path("/usr/sbin/slick-greeter").exists() or dpkg_installed("slick-greeter")

def backup_file(path, backup_root, manifest):
    path = Path(path)
    item = {"path": str(path), "existed": path.exists()}
    if path.exists():
        rel = str(path).lstrip("/").replace("/", "__")
        dst = backup_root / rel
        shutil.copy2(path, dst)
        item["backup"] = str(dst)
    manifest.append(item)

def write_conf(path, text):
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(text, encoding="utf-8")
    path.chmod(0o644)

def summary():
    print("SentinelOS Login Screen")
    print(f"version: {VERSION}")
    print("public_theme: SentinelOS Dark/Cyan")
    print("display_manager_replacement: no")
    print("touch_passwords_or_users: no")
    print("background:", BG)
    print("brand:", BRAND)
    print("lightdm_detected:", "yes" if lightdm_present() else "no")
    print("gtk_greeter_detected:", "yes" if gtk_greeter_present() else "no")
    print("slick_greeter_detected:", "yes" if slick_present() else "no")
    print("policy:", POLICY)

def apply(confirm):
    if os.geteuid() != 0:
        print("ERROR: --apply requires root", file=sys.stderr)
        return 2
    if confirm != CONFIRM_APPLY:
        print(f"ERROR: missing --confirm {CONFIRM_APPLY}", file=sys.stderr)
        return 2
    if not BG.exists() or not BRAND.exists():
        print("ERROR: login assets missing", file=sys.stderr)
        return 1

    STATE.mkdir(parents=True, exist_ok=True)
    BACKUPS.mkdir(parents=True, exist_ok=True)
    stamp = datetime.now().strftime("%Y%m%d-%H%M%S")
    backup_root = BACKUPS / stamp
    backup_root.mkdir(parents=True, exist_ok=True)
    manifest = {
        "version": VERSION,
        "timestamp": datetime.now().isoformat(),
        "backup_root": str(backup_root),
        "files": []
    }

    if not lightdm_present():
        print("lightdm: not detected")
        print("apply: skipped safely")
        ACTIVE.write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8")
        return 0

    wrote = 0
    if gtk_greeter_present() or Path("/etc/lightdm").exists():
        backup_file(GTK_CONF, backup_root, manifest["files"])
        write_conf(GTK_CONF, GTK_TEXT)
        print("configured:", GTK_CONF)
        wrote += 1

    if slick_present():
        backup_file(SLICK_CONF, backup_root, manifest["files"])
        write_conf(SLICK_CONF, SLICK_TEXT)
        print("configured:", SLICK_CONF)
        wrote += 1

    ACTIVE.write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8")
    print("backup_manifest:", ACTIVE)
    print("configs_written:", wrote)
    print("apply: ok")
    print("note: reboot or restart LightDM to see the login screen")
    return 0

def restore(confirm):
    if os.geteuid() != 0:
        print("ERROR: --restore requires root", file=sys.stderr)
        return 2
    if confirm != CONFIRM_RESTORE:
        print(f"ERROR: missing --confirm {CONFIRM_RESTORE}", file=sys.stderr)
        return 2
    if not ACTIVE.exists():
        print("restore: no active restore manifest found")
        return 0

    data = json.loads(ACTIVE.read_text(encoding="utf-8"))
    for item in data.get("files", []):
        path = Path(item["path"])
        if item.get("existed") and item.get("backup"):
            src = Path(item["backup"])
            if src.exists():
                path.parent.mkdir(parents=True, exist_ok=True)
                shutil.copy2(src, path)
                print("restored:", path)
        else:
            if path.exists():
                path.unlink()
                print("removed:", path)
    print("restore: ok")
    return 0

def verify():
    ok = True
    if not POLICY.exists():
        print("missing:", POLICY)
        ok = False
    if not BG.exists():
        print("missing:", BG)
        ok = False
    if not BRAND.exists():
        print("missing:", BRAND)
        ok = False

    if lightdm_present():
        print("lightdm: detected")
        have = False
        if GTK_CONF.exists() and str(BG) in GTK_CONF.read_text(encoding="utf-8", errors="ignore"):
            print("gtk_greeter_config: ok")
            have = True
        elif gtk_greeter_present() or Path("/etc/lightdm").exists():
            print("gtk_greeter_config: missing")
            ok = False

        if slick_present():
            if SLICK_CONF.exists() and str(BG) in SLICK_CONF.read_text(encoding="utf-8", errors="ignore"):
                print("slick_greeter_config: ok")
                have = True
            else:
                print("slick_greeter_config: missing")
                ok = False
        if not have and not (gtk_greeter_present() or slick_present() or Path("/etc/lightdm").exists()):
            print("greeter_config: skipped/no supported greeter detected")
    else:
        print("lightdm: not detected/skipped-safe")

    for path in (POLICY, BG, BRAND):
        if path.exists():
            text = path.read_text(encoding="utf-8", errors="ignore")
            if any(term.lower() in text.lower() for term in ("AEGIS Gold", "gold theme", "gold desktop", "special AEGIS theme", "hidden desktop mode")):
                print("forbidden public wording present in:", path)
                ok = False

    print("verify: ok" if ok else "verify: failed")
    return 0 if ok else 1

def main(argv):
    if len(argv) < 2 or argv[1] in ("--help", "-h"):
        print("sentinelos-login-screen --summary|--verify|--apply --confirm APPLY_SENTINELOS_LOGIN_SCREEN|--restore --confirm RESTORE_SENTINELOS_LOGIN_SCREEN")
        return 0
    if argv[1] == "--summary":
        summary()
        return 0
    if argv[1] == "--verify":
        return verify()
    if argv[1] == "--apply":
        confirm = argv[3] if len(argv) >= 4 and argv[2] == "--confirm" else ""
        return apply(confirm)
    if argv[1] == "--restore":
        confirm = argv[3] if len(argv) >= 4 and argv[2] == "--confirm" else ""
        return restore(confirm)
    print("ERROR: unknown command", file=sys.stderr)
    return 2

if __name__ == "__main__":
    raise SystemExit(main(sys.argv))
