package main

import (
	"context"
	"fmt"
	"os"
	"strings"

	"github.com/AvengeMedia/DankMaterialShell/core/internal/greeter"
	"github.com/AvengeMedia/DankMaterialShell/core/internal/privesc"
)

// runit (Void Linux) service helpers. Services live in /etc/sv and are "enabled"
// by symlinking them into the /var/service supervision dir, so the greeter
// commands branch on isRunit() instead of shelling systemctl.

const (
	runitSvDir      = "/etc/sv"
	runitServiceDir = "/var/service"
)

// isRunit reports whether this system is supervised by runit (Void Linux).
func isRunit() bool {
	if fi, err := os.Stat("/run/runit"); err == nil && fi.IsDir() {
		return true
	}
	if _, err := os.Stat("/run/systemd/system"); err == nil {
		return false
	}
	if fi, err := os.Stat(runitServiceDir); err == nil && fi.IsDir() {
		return true
	}
	return false
}

func runitServiceInstalled(name string) bool {
	fi, err := os.Stat(runitSvDir + "/" + name)
	return err == nil && fi.IsDir()
}

func runitServiceEnabled(name string) bool {
	_, err := os.Lstat(runitServiceDir + "/" + name)
	return err == nil
}

// enableRunitService links a service into /var/service (idempotent).
func enableRunitService(name string) error {
	if !runitServiceInstalled(name) {
		return fmt.Errorf("runit service %q not found in %s", name, runitSvDir)
	}
	if runitServiceEnabled(name) {
		return nil
	}
	return privesc.Run(context.Background(), "", "ln", "-sf",
		runitSvDir+"/"+name, runitServiceDir+"/"+name)
}

// disableRunitService removes a service's supervision symlink.
func disableRunitService(name string) error {
	if !runitServiceEnabled(name) {
		return nil
	}
	return privesc.Run(context.Background(), "", "rm", "-f",
		runitServiceDir+"/"+name)
}

// ensureRunitSeat sets up the seat access a Wayland greeter needs on runit (the
// equivalent of logind on systemd): enables seatd and adds the greeter user to
// the seat/video/input groups. Failures are reported but non-fatal.
func ensureRunitSeat(greeterUser string) {
	if runitServiceInstalled("seatd") {
		if err := enableRunitService("seatd"); err != nil {
			fmt.Printf("  ⚠ could not enable seatd: %v\n", err)
		} else {
			fmt.Println("  ✓ seatd enabled")
		}
	} else {
		fmt.Println("  ⚠ seatd not installed — the greeter compositor needs it for GPU/seat access")
	}
	if err := privesc.Run(context.Background(), "", "usermod", "-aG", "_seatd,video,input", greeterUser); err != nil {
		fmt.Printf("  ⚠ could not add %s to seat groups: %v\n", greeterUser, err)
	} else {
		fmt.Printf("  ✓ %s added to seat groups (_seatd, video, input)\n", greeterUser)
	}
}

// ensureVoidLogindGreeter configures the elogind-backed greeter on Void.
func ensureVoidLogindGreeter(greeterUser string) {
	for _, service := range []string{"dbus", "elogind"} {
		if err := enableRunitService(service); err != nil {
			fmt.Printf("  ⚠ could not enable %s: %v\n", service, err)
		} else {
			fmt.Printf("  ✓ %s enabled\n", service)
		}
	}
	greeter.EnsureVoidGreetdRunScript(func(msg string) { fmt.Println("  " + msg) }, "")
	if runitServiceEnabled("seatd") {
		if err := disableRunitService("seatd"); err != nil {
			fmt.Printf("  ⚠ could not disable seatd: %v\n", err)
		} else {
			fmt.Println("  ✓ seatd disabled (elogind manages the seat)")
		}
	}
	if err := privesc.Run(context.Background(), "", "usermod", "-aG", "video,input", greeterUser); err != nil {
		fmt.Printf("  ⚠ could not add %s to video/input groups: %v\n", greeterUser, err)
	} else {
		fmt.Printf("  ✓ %s added to video/input groups (elogind manages the seat)\n", greeterUser)
	}
}

// ensureGreetdPamRundir provides XDG_RUNTIME_DIR to runit greeter sessions.
func ensureGreetdPamRundir() {
	const pamPath = "/etc/pam.d/greetd"
	data, err := os.ReadFile(pamPath)
	if err != nil {
		fmt.Printf("  ⚠ could not read %s: %v\n", pamPath, err)
		return
	}
	if strings.Contains(string(data), "pam_rundir") {
		return
	}
	line := "session    optional    pam_rundir.so"
	if err := privesc.Run(context.Background(), "", "sh", "-c",
		fmt.Sprintf("printf '%%s\\n' %q >> %s", line, pamPath)); err != nil {
		fmt.Printf("  ⚠ could not add pam_rundir to %s: %v\n", pamPath, err)
		return
	}
	fmt.Println("  ✓ pam_rundir added to greetd PAM (provides XDG_RUNTIME_DIR for the session)")
}

// startGreeterHint returns the init-appropriate "start greetd now" command.
func startGreeterHint() string {
	if isRunit() {
		return "  sudo sv up greetd"
	}
	return "  sudo systemctl start greetd"
}
