package platform

import (
	"runtime"
	"strings"
)

type OS string

const (
	Linux   OS = "linux"
	MacOS   OS = "darwin"
	Windows OS = "windows"
	Unknown OS = "unknown"
)

type Arch string

const (
	AMD64 Arch = "amd64"
	ARM64 Arch = "arm64"
	ARM   Arch = "arm"
	X86   Arch = "386"
)

type SystemInfo struct {
	OS             OS     `json:"os"`
	OSName         string `json:"os_name"`
	Arch           Arch   `json:"arch"`
	IsWSL          bool   `json:"is_wsl"`
	Shell          string `json:"shell"`
	Terminal       string `json:"terminal"`
	PackageManager string `json:"package_manager"`
}

func Detect() SystemInfo {
	info := SystemInfo{
		OS:   OS(runtime.GOOS),
		Arch: Arch(runtime.GOARCH),
	}

	info.IsWSL = detectWSL()
	info.OSName = detectOSName(info.OS, info.IsWSL)
	info.Shell = detectShell()
	info.Terminal = detectTerminal()
	info.PackageManager = detectPackageManager(info.OS)

	return info
}

func detectOSName(os OS, isWSL bool) string {
	switch os {
	case Linux:
		if name := readOSReleaseName(); name != "" {
			if isWSL {
				return name + " (WSL)"
			}
			return name
		}
		if isWSL {
			return "Linux (WSL)"
		}
		return "Linux"
	case MacOS:
		if v := readMacOSVersion(); v != "" {
			return "macOS " + v
		}
		return "macOS"
	case Windows:
		if v := readWindowsVersion(); v != "" {
			return v
		}
		return "Windows"
	}
	return string(os)
}

func detectWSL() bool {
	return fileContains("/proc/version", "microsoft") ||
		fileContains("/proc/version", "WSL")
}

func detectShell() string {
	shells := []string{"zsh", "bash", "fish", "pwsh", "powershell"}
	for _, s := range shells {
		if _, err := execLookPath(s); err == nil {
			return s
		}
	}
	return "sh"
}

func detectTerminal() string {
	terms := []string{
		"hyper", "alacritty", "kitty", "wezterm", "ghostty",
		"windows-terminal", "gnome-terminal", "konsole",
		"xterm", "tilix", "terminator",
	}
	for _, t := range terms {
		if _, err := execLookPath(t); err == nil {
			return t
		}
	}
	return "unknown"
}

func detectPackageManager(os OS) string {
	managers := map[string][]string{
		"linux":   {"apt", "dnf", "pacman", "zypper", "nix", "apk", "snap", "flatpak"},
		"darwin":  {"brew", "nix"},
		"windows": {"winget", "choco", "scoop"},
	}

	if list, ok := managers[string(os)]; ok {
		for _, mgr := range list {
			if _, err := execLookPath(mgr); err == nil {
				return mgr
			}
		}
	}
	return "unknown"
}

func (s SystemInfo) String() string {
	parts := []string{
		"OS: " + string(s.OS),
	}
	if s.OSName != "" {
		parts = append(parts, "Name: "+s.OSName)
	}
	parts = append(parts, "Arch: "+string(s.Arch))
	if s.IsWSL {
		parts = append(parts, "WSL: yes")
	}
	parts = append(parts, "Shell: "+s.Shell)
	parts = append(parts, "Terminal: "+s.Terminal)
	parts = append(parts, "PackageManager: "+s.PackageManager)
	return strings.Join(parts, ", ")
}
