//go:build !windows

package deploy

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

	"crypto-miner-agent/config"
)

func CurrentExecutable() (string, error) {
	path, err := os.Executable()
	if err != nil {
		return filepath.Abs(os.Args[0])
	}
	return filepath.Abs(path)
}

func configureAutoStart(cfg config.RuntimeConfig, binPath string) error {
	switch runtime.GOOS {
	case "darwin":
		return configureLaunchAgent(cfg, binPath)
	default:
		return configureSystemdUser(cfg, binPath)
	}
}

func configureRunMode(cfg config.RuntimeConfig, installedBin string) error {
	if cfg.RunAs == "scheduled" || cfg.RunAs == "service" {
		return configureAutoStart(cfg, installedBin)
	}
	return nil
}

func configureSystemdUser(cfg config.RuntimeConfig, binPath string) error {
	unitName := PersistenceKeyName(cfg) + ".service"
	unitDir := filepath.Join(os.Getenv("HOME"), ".config", "systemd", "user")
	if err := os.MkdirAll(unitDir, 0755); err != nil {
		return err
	}
	unitPath := filepath.Join(unitDir, unitName)
	content := fmt.Sprintf(`[Unit]
Description=AetherForge Worker %s
After=network.target

[Service]
Type=simple
ExecStart=%s %s
Restart=always
RestartSec=60

[Install]
WantedBy=default.target
`, cfg.WorkerName, binPath, runFlag)
	if err := os.WriteFile(unitPath, []byte(content), 0644); err != nil {
		return err
	}
	_ = exec.Command("systemctl", "--user", "daemon-reload").Run()
	_ = exec.Command("systemctl", "--user", "enable", unitName).Run()
	_ = exec.Command("systemctl", "--user", "start", unitName).Run()
	return nil
}

func configureLaunchAgent(cfg config.RuntimeConfig, binPath string) error {
	label := "com.aetherforge." + sanitizeName(PersistenceKeyName(cfg))
	plistDir := filepath.Join(os.Getenv("HOME"), "Library", "LaunchAgents")
	if err := os.MkdirAll(plistDir, 0755); err != nil {
		return err
	}
	plistPath := filepath.Join(plistDir, label+".plist")
	content := fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key><string>%s</string>
  <key>ProgramArguments</key>
  <array><string>%s</string><string>%s</string></array>
  <key>RunAtLoad</key><true/>
  <key>KeepAlive</key><true/>
  <key>ProcessType</key><string>Background</string>
</dict>
</plist>
`, label, binPath, runFlag)
	if err := os.WriteFile(plistPath, []byte(content), 0644); err != nil {
		return err
	}
	_ = exec.Command("launchctl", "load", plistPath).Run()
	return nil
}

func applyDetachedStart(cmd *exec.Cmd) {
	if cmd == nil {
		return
	}
	cmd.Stdin = nil
	cmd.Stdout = nil
	cmd.Stderr = nil
}

func HostOSVersion() string {
	out, err := exec.Command("uname", "-sr").CombinedOutput()
	if err != nil {
		return runtime.GOOS
	}
	return strings.TrimSpace(string(out))
}

func killWorkerProcess(cfg config.RuntimeConfig) {
	name := BinaryName(cfg)
	if runtime.GOOS == "darwin" {
		_ = exec.Command("pkill", "-f", name).Run()
	} else {
		_ = exec.Command("pkill", "-x", cfg.EffectiveProcessName()).Run()
	}
}

func removePersistence(cfg config.RuntimeConfig) {
	keyName := PersistenceKeyName(cfg)
	switch runtime.GOOS {
	case "darwin":
		label := "com.aetherforge." + sanitizeName(keyName)
		plistPath := filepath.Join(os.Getenv("HOME"), "Library", "LaunchAgents", label+".plist")
		_ = exec.Command("launchctl", "unload", plistPath).Run()
		_ = os.Remove(plistPath)
	default:
		unitName := keyName + ".service"
		_ = exec.Command("systemctl", "--user", "disable", unitName).Run()
		_ = exec.Command("systemctl", "--user", "stop", unitName).Run()
		_ = os.Remove(filepath.Join(os.Getenv("HOME"), ".config", "systemd", "user", unitName))
	}
}

func selfUninstallSpawn(installDir string) {
	script := fmt.Sprintf("#!/bin/sh\nsleep 2\nrm -rf %q\n", installDir)
	tmp := filepath.Join(os.TempDir(), "af-uninstall.sh")
	_ = os.WriteFile(tmp, []byte(script), 0755)
	cmd := exec.Command("/bin/sh", tmp)
	_ = cmd.Start()
}
