package platform

import (
	"os"
	"os/exec"
	"runtime"
	"strings"

	"gitgud.io/mike/mpv-manager/pkg/log"
)

func detectCPU() CPUInfo {
	info := CPUInfo{
		Features: []string{},
	}

	if runtime.GOOS == "windows" {
		info = detectCPUWindows()
	} else if runtime.GOOS == "linux" {
		info = detectCPULinux()
	} else if runtime.GOOS == "darwin" {
		info = detectCPUDarwin()
	}

	info.SupportsAVX2 = checkAVX2(info.Features)
	info.SupportsAVX512 = checkAVX512(info.Features)
	info.SupportsNEON = checkNEON(info.Features)
	// Normalize vendor name for consistent color coding and display
	info.VendorDisplay = getVendorDisplay(info.Vendor)
	info.Vendor = info.VendorDisplay
	// Only set ArchitectureLevel if not already set (Windows sets it directly via cpuid)
	if info.ArchitectureLevel == "" {
		info.ArchitectureLevel = detectArchitectureLevel(info.Features)
	}

	return info
}

func detectCPULinux() CPUInfo {
	info := CPUInfo{}

	if data, err := os.ReadFile("/proc/cpuinfo"); err == nil {
		content := string(data)
		lines := strings.Split(content, "\n")
		for _, line := range lines {
			line = strings.TrimSpace(line)
			if strings.HasPrefix(line, "vendor_id") {
				parts := strings.SplitN(line, ":", 2)
				if len(parts) == 2 {
					info.Vendor = strings.TrimSpace(parts[1])
				}
			} else if strings.HasPrefix(line, "model name") {
				parts := strings.SplitN(line, ":", 2)
				if len(parts) == 2 {
					info.Model = strings.TrimSpace(parts[1])
				}
			} else if strings.HasPrefix(line, "flags") || strings.HasPrefix(line, "Features") {
				parts := strings.SplitN(line, ":", 2)
				if len(parts) == 2 {
					features := strings.Fields(strings.TrimSpace(parts[1]))
					info.Features = features
				}
			}
		}
	} else {
		log.Warn("Failed to read /proc/cpuinfo: " + err.Error())
	}

	return info
}

func detectCPUDarwin() CPUInfo {
	info := CPUInfo{
		Vendor: "Apple",
	}

	if output, err := exec.Command("sysctl", "-n", "machdep.cpu.brand_string").Output(); err == nil {
		info.Model = strings.TrimSpace(string(output))
	} else if runtime.GOARCH == "arm64" {
		info.Model = "Apple Silicon"
	} else {
		info.Model = "Intel"
	}

	// Set features based on architecture (ALWAYS, not just when sysctl fails)
	if runtime.GOARCH == "arm64" {
		info.Features = []string{"arm64", "neon"}
	} else {
		// Intel Mac - try to get actual features, or use reasonable defaults
		info.Features = []string{"x86-64", "sse", "sse2", "sse3", "ssse3", "sse4_1", "sse4_2"}
		// Could also check for AVX2 via sysctl hw.optional.avx2_0
	}

	return info
}

func checkAVX2(features []string) bool {
	for _, feature := range features {
		if strings.Contains(strings.ToLower(feature), "avx2") {
			return true
		}
	}
	return false
}

func checkAVX512(features []string) bool {
	for _, feature := range features {
		if strings.Contains(strings.ToLower(feature), "avx512") {
			return true
		}
	}
	return false
}

func checkNEON(features []string) bool {
	for _, feature := range features {
		if strings.Contains(strings.ToLower(feature), "neon") {
			return true
		}
	}
	return false
}

func getVendorDisplay(vendor string) string {
	switch vendor {
	case "GenuineIntel":
		return "Intel"
	case "AuthenticAMD":
		return "AMD"
	case "nvidia":
		return "NVIDIA"
	case "amd":
		return "AMD"
	case "intel":
		return "Intel"
	case "apple":
		return "Apple"
	default:
		return vendor
	}
}

func detectArchitectureLevel(features []string) string {
	// Check for ARM architecture first
	for _, feature := range features {
		featureLower := strings.ToLower(feature)
		if strings.Contains(featureLower, "arm64") ||
			strings.Contains(featureLower, "aarch64") ||
			strings.Contains(featureLower, "neon") {
			return "arm64"
		}
	}

	// x86-64 detection
	hasAVX2 := false
	hasAVX512 := false

	for _, feature := range features {
		featureLower := strings.ToLower(feature)
		if strings.Contains(featureLower, "avx2") {
			hasAVX2 = true
		}
		if strings.Contains(featureLower, "avx512") {
			hasAVX512 = true
		}
	}

	if hasAVX512 {
		return "x86-64-v4"
	}
	if hasAVX2 {
		return "x86-64-v3"
	}
	return "x86-64-v2"
}

func (p *Platform) SupportsX86_64_v3() bool {
	return (p.Arch == "amd64" || p.Arch == "x86_64") && p.CPUInfo.SupportsAVX2
}
