package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

func isAutoStartEnabled(appPath string) bool {
	serviceFile := autoStartServiceFile(appPath)
	kioskInfof("autostart check begin service=%s expectedExec=%s expectedWorkdir=%s", serviceFile, appPath, filepath.Dir(appPath))

	content, err := os.ReadFile(serviceFile)
	if err != nil {
		kioskWarnf("autostart service read failed service=%s err=%v", serviceFile, err)
		return false
	}
	matches := autoStartServiceMatches(string(content), appPath)
	kioskInfof("autostart service match result service=%s matches=%v", serviceFile, matches)
	return matches
}

func enableAutoStart(appPath string) error {
	serviceFile := autoStartServiceFile(appPath)
	kioskInfof("autostart setup begin service=%s exec=%s workdir=%s", serviceFile, appPath, filepath.Dir(appPath))

	content := autoStartServiceContent(appPath)
	kioskDebugf("autostart service content:\n%s", content)
	cmd := exec.Command("sudo", "tee", serviceFile)
	cmd.Stdin = strings.NewReader(content)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		kioskErrorf("write autostart service failed service=%s err=%v", serviceFile, err)
		return err
	}
	kioskInfof("write autostart service success service=%s", serviceFile)

	cmd = exec.Command("sudo", "systemctl", "daemon-reload")
	if err := cmd.Run(); err != nil {
		kioskErrorf("systemctl daemon-reload failed err=%v", err)
		return err
	}
	kioskInfof("systemctl daemon-reload success")

	cmd = exec.Command("sudo", "systemctl", "enable", autoStartServiceName(appPath))
	if err := cmd.Run(); err != nil {
		kioskErrorf("systemctl enable failed service=%s err=%v", autoStartServiceName(appPath), err)
		return err
	}
	kioskInfof("systemctl enable success service=%s", autoStartServiceName(appPath))
	return nil
}

func autoStartServiceName(appPath string) string {
	return strings.TrimSuffix(filepath.Base(appPath), filepath.Ext(appPath)) + ".service"
}

func autoStartServiceFile(appPath string) string {
	return filepath.Join("/etc/systemd/system", autoStartServiceName(appPath))
}

func autoStartServiceContent(appPath string) string {
	appName := strings.TrimSuffix(filepath.Base(appPath), filepath.Ext(appPath))
	return fmt.Sprintf(`[Unit]
Description=%s Background Service
Wants=network-online.target
After=network-online.target graphical.target display-manager.service

[Service]
Type=simple
ExecStart=%s
Restart=on-failure
RestartSec=10
User=root
WorkingDirectory=%s
Environment=DISPLAY=:0

[Install]
WantedBy=graphical.target
`,
		appName,
		appPath,
		filepath.Dir(appPath))
}

func autoStartServiceMatches(content string, appPath string) bool {
	execStart := normalizeSystemdValue(systemdUnitValue(content, "ExecStart"))
	workingDirectory := normalizeSystemdValue(systemdUnitValue(content, "WorkingDirectory"))
	wants := normalizeSystemdValue(systemdUnitValue(content, "Wants"))
	after := normalizeSystemdValue(systemdUnitValue(content, "After"))
	environment := normalizeSystemdValue(systemdUnitValue(content, "Environment"))
	wantedBy := normalizeSystemdValue(systemdUnitValue(content, "WantedBy"))
	expectedWorkdir := filepath.Dir(appPath)
	expectedWants := "network-online.target"
	expectedAfter := "network-online.target graphical.target display-manager.service"
	expectedEnvironment := "DISPLAY=:0"
	expectedWantedBy := "graphical.target"
	matches := execStart == appPath &&
		workingDirectory == expectedWorkdir &&
		wants == expectedWants &&
		after == expectedAfter &&
		environment == expectedEnvironment &&
		wantedBy == expectedWantedBy
	kioskInfof("autostart service fields execStart=%s expectedExec=%s workingDirectory=%s expectedWorkdir=%s wants=%s expectedWants=%s after=%s expectedAfter=%s environment=%s expectedEnvironment=%s wantedBy=%s expectedWantedBy=%s matches=%v", execStart, appPath, workingDirectory, expectedWorkdir, wants, expectedWants, after, expectedAfter, environment, expectedEnvironment, wantedBy, expectedWantedBy, matches)

	return matches
}

func systemdUnitValue(content string, key string) string {
	for _, line := range strings.Split(content, "\n") {
		line = strings.TrimSpace(line)
		if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, ";") {
			continue
		}
		name, value, ok := strings.Cut(line, "=")
		if !ok || strings.TrimSpace(name) != key {
			continue
		}
		return strings.TrimSpace(value)
	}
	return ""
}

func normalizeSystemdValue(value string) string {
	return strings.Trim(strings.TrimSpace(value), `"'`)
}
