package ux

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

// TroubleshootingGuide provides troubleshooting information and diagnostics
type TroubleshootingGuide struct {
	verbose bool
}

// NewTroubleshootingGuide creates a new troubleshooting guide
func NewTroubleshootingGuide(verbose bool) *TroubleshootingGuide {
	return &TroubleshootingGuide{verbose: verbose}
}

// DiagnosticResult represents the result of a diagnostic check
type DiagnosticResult struct {
	Check     string
	Status    string
	Message   string
	Details   string
	Fix       string
	Critical  bool
}

// RunDiagnostics runs comprehensive system diagnostics
func (t *TroubleshootingGuide) RunDiagnostics() []DiagnosticResult {
	var results []DiagnosticResult

	// Check required tools
	results = append(results, t.checkRequiredTools()...)
	
	// Check system resources
	results = append(results, t.checkSystemResources()...)
	
	// Check permissions
	results = append(results, t.checkPermissions()...)
	
	// Check network connectivity
	results = append(results, t.checkNetworkConnectivity()...)
	
	// Check container runtime
	results = append(results, t.checkContainerRuntime()...)

	return results
}

// checkRequiredTools checks for required system tools
func (t *TroubleshootingGuide) checkRequiredTools() []DiagnosticResult {
	var results []DiagnosticResult

	requiredTools := map[string]string{
		"apt-cache": "Required for package dependency resolution",
		"podman":    "Required for container operations",
		"qemu-img":  "Required for image format conversion",
		"file":      "Required for file type detection",
	}

	for tool, description := range requiredTools {
		result := t.checkTool(tool, description)
		results = append(results, result)
	}

	return results
}

// checkTool checks if a specific tool is available
func (t *TroubleshootingGuide) checkTool(tool, description string) DiagnosticResult {
	_, err := exec.LookPath(tool)
	if err != nil {
		return DiagnosticResult{
			Check:    fmt.Sprintf("Tool: %s", tool),
			Status:   "❌ Missing",
			Message:  fmt.Sprintf("%s is not installed or not in PATH", tool),
			Details:  description,
			Fix:      fmt.Sprintf("Install %s: sudo apt install %s", tool, t.getPackageName(tool)),
			Critical: true,
		}
	}

	return DiagnosticResult{
		Check:    fmt.Sprintf("Tool: %s", tool),
		Status:   "✅ Available",
		Message:  fmt.Sprintf("%s is installed and accessible", tool),
		Details:  description,
		Critical: false,
	}
}

// getPackageName returns the package name for a tool
func (t *TroubleshootingGuide) getPackageName(tool string) string {
	packageMap := map[string]string{
		"apt-cache": "apt",
		"podman":    "podman",
		"qemu-img":  "qemu-utils",
		"file":      "file",
	}
	
	if pkg, exists := packageMap[tool]; exists {
		return pkg
	}
	return tool
}

// checkSystemResources checks system resource availability
func (t *TroubleshootingGuide) checkSystemResources() []DiagnosticResult {
	var results []DiagnosticResult

	// Check available disk space
	results = append(results, t.checkDiskSpace())
	
	// Check available memory
	results = append(results, t.checkMemory())

	return results
}

// checkDiskSpace checks available disk space
func (t *TroubleshootingGuide) checkDiskSpace() DiagnosticResult {
	// Check current directory disk space
	var stat syscall.Statfs_t
	err := syscall.Statfs(".", &stat)
	if err != nil {
		return DiagnosticResult{
			Check:    "Disk Space",
			Status:   "⚠️  Unknown",
			Message:  "Cannot determine available disk space",
			Details:  "Failed to get filesystem statistics",
			Fix:      "Check disk space manually: df -h",
			Critical: false,
		}
	}

	// Calculate available space in GB
	availableBytes := stat.Bavail * uint64(stat.Bsize)
	availableGB := float64(availableBytes) / (1024 * 1024 * 1024)

	if availableGB < 5.0 {
		return DiagnosticResult{
			Check:    "Disk Space",
			Status:   "❌ Low",
			Message:  fmt.Sprintf("Only %.1f GB available", availableGB),
			Details:  "Image building requires at least 5GB of free space",
			Fix:      "Free up disk space or use a different directory",
			Critical: true,
		}
	}

	return DiagnosticResult{
		Check:    "Disk Space",
		Status:   "✅ Sufficient",
		Message:  fmt.Sprintf("%.1f GB available", availableGB),
		Details:  "Adequate disk space for image building",
		Critical: false,
	}
}

// checkMemory checks available system memory
func (t *TroubleshootingGuide) checkMemory() DiagnosticResult {
	// Read /proc/meminfo for memory information
	data, err := os.ReadFile("/proc/meminfo")
	if err != nil {
		return DiagnosticResult{
			Check:    "Memory",
			Status:   "⚠️  Unknown",
			Message:  "Cannot determine available memory",
			Details:  "Failed to read memory information",
			Fix:      "Check memory manually: free -h",
			Critical: false,
		}
	}

	// Parse available memory (simplified)
	lines := strings.Split(string(data), "\n")
	var memTotal, memAvailable int64
	
	for _, line := range lines {
		if strings.HasPrefix(line, "MemTotal:") {
			fmt.Sscanf(line, "MemTotal: %d kB", &memTotal)
		} else if strings.HasPrefix(line, "MemAvailable:") {
			fmt.Sscanf(line, "MemAvailable: %d kB", &memAvailable)
		}
	}

	if memTotal == 0 {
		return DiagnosticResult{
			Check:    "Memory",
			Status:   "⚠️  Unknown",
			Message:  "Cannot parse memory information",
			Details:  "Failed to parse /proc/meminfo",
			Fix:      "Check memory manually: free -h",
			Critical: false,
		}
	}

	memTotalGB := float64(memTotal) / (1024 * 1024)
	memAvailableGB := float64(memAvailable) / (1024 * 1024)

	if memTotalGB < 2.0 {
		return DiagnosticResult{
			Check:    "Memory",
			Status:   "❌ Insufficient",
			Message:  fmt.Sprintf("Only %.1f GB total memory", memTotalGB),
			Details:  "Image building requires at least 2GB of RAM",
			Fix:      "Add more RAM or use a system with more memory",
			Critical: true,
		}
	}

	if memAvailableGB < 1.0 {
		return DiagnosticResult{
			Check:    "Memory",
			Status:   "⚠️  Low",
			Message:  fmt.Sprintf("Only %.1f GB available memory", memAvailableGB),
			Details:  "Low available memory may cause build failures",
			Fix:      "Close other applications or add more RAM",
			Critical: false,
		}
	}

	return DiagnosticResult{
		Check:    "Memory",
		Status:   "✅ Sufficient",
		Message:  fmt.Sprintf("%.1f GB total, %.1f GB available", memTotalGB, memAvailableGB),
		Details:  "Adequate memory for image building",
		Critical: false,
	}
}

// checkPermissions checks file and directory permissions
func (t *TroubleshootingGuide) checkPermissions() []DiagnosticResult {
	var results []DiagnosticResult

	// Check current directory write permissions
	results = append(results, t.checkWritePermission(".", "Current directory"))
	
	// Check /tmp write permissions
	results = append(results, t.checkWritePermission("/tmp", "Temporary directory"))

	return results
}

// checkWritePermission checks write permission for a directory
func (t *TroubleshootingGuide) checkWritePermission(path, description string) DiagnosticResult {
	// Try to create a test file
	testFile := filepath.Join(path, ".debian-bootc-image-builder-test")
	err := os.WriteFile(testFile, []byte("test"), 0644)
	if err != nil {
		// Clean up if file was created
		os.Remove(testFile)
		return DiagnosticResult{
			Check:    fmt.Sprintf("Write Permission: %s", description),
			Status:   "❌ Denied",
			Message:  fmt.Sprintf("Cannot write to %s", path),
			Details:  fmt.Sprintf("Permission denied: %v", err),
			Fix:      fmt.Sprintf("Check permissions: ls -la %s", path),
			Critical: true,
		}
	}

	// Clean up test file
	os.Remove(testFile)
	return DiagnosticResult{
		Check:    fmt.Sprintf("Write Permission: %s", description),
		Status:   "✅ Allowed",
		Message:  fmt.Sprintf("Can write to %s", path),
		Details:  "Write permissions are sufficient",
		Critical: false,
	}
}

// checkNetworkConnectivity checks network connectivity for required services
func (t *TroubleshootingGuide) checkNetworkConnectivity() []DiagnosticResult {
	var results []DiagnosticResult

	// Check basic internet connectivity
	results = append(results, t.checkConnectivity("8.8.8.8", "Internet connectivity"))
	
	// Check Debian repository connectivity
	results = append(results, t.checkConnectivity("deb.debian.org", "Debian repositories"))

	return results
}

// checkConnectivity checks network connectivity to a host
func (t *TroubleshootingGuide) checkConnectivity(host, description string) DiagnosticResult {
	cmd := exec.Command("ping", "-c", "1", "-W", "5", host)
	err := cmd.Run()
	if err != nil {
		return DiagnosticResult{
			Check:    fmt.Sprintf("Network: %s", description),
			Status:   "❌ Failed",
			Message:  fmt.Sprintf("Cannot reach %s", host),
			Details:  "Network connectivity issue",
			Fix:      "Check network connection and firewall settings",
			Critical: false, // Not critical for basic functionality
		}
	}

	return DiagnosticResult{
		Check:    fmt.Sprintf("Network: %s", description),
		Status:   "✅ Connected",
		Message:  fmt.Sprintf("Can reach %s", host),
		Details:  "Network connectivity is working",
		Critical: false,
	}
}

// checkContainerRuntime checks container runtime availability
func (t *TroubleshootingGuide) checkContainerRuntime() []DiagnosticResult {
	var results []DiagnosticResult

	// Check if podman is running
	cmd := exec.Command("podman", "version")
	err := cmd.Run()
	if err != nil {
		results = append(results, DiagnosticResult{
			Check:    "Container Runtime",
			Status:   "❌ Failed",
			Message:  "Podman is not working properly",
			Details:  "Cannot execute podman version command",
			Fix:      "Check podman installation and configuration",
			Critical: true,
		})
	} else {
		results = append(results, DiagnosticResult{
			Check:    "Container Runtime",
			Status:   "✅ Working",
			Message:  "Podman is working properly",
			Details:  "Container runtime is functional",
			Critical: false,
		})
	}

	return results
}

// PrintDiagnostics prints diagnostic results
func (t *TroubleshootingGuide) PrintDiagnostics(results []DiagnosticResult) {
	fmt.Println("🔍 System Diagnostics:")
	fmt.Println()

	criticalIssues := 0
	warnings := 0

	for _, result := range results {
		fmt.Printf("%s %s: %s\n", result.Status, result.Check, result.Message)
		
		if t.verbose && result.Details != "" {
			fmt.Printf("   Details: %s\n", result.Details)
		}
		
		if result.Fix != "" {
			fmt.Printf("   Fix: %s\n", result.Fix)
		}
		
		if result.Critical {
			criticalIssues++
		} else if strings.Contains(result.Status, "⚠️") {
			warnings++
		}
		
		fmt.Println()
	}

	// Summary
	if criticalIssues > 0 {
		fmt.Printf("❌ Found %d critical issues that must be resolved\n", criticalIssues)
	} else if warnings > 0 {
		fmt.Printf("⚠️  Found %d warnings (non-critical)\n", warnings)
	} else {
		fmt.Println("✅ All diagnostics passed - system is ready")
	}
}

// GetCommonSolutions returns common solutions for frequent issues
func (t *TroubleshootingGuide) GetCommonSolutions() map[string][]string {
	return map[string][]string{
		"apt-cache failed": {
			"Ensure apt-cache is installed: sudo apt install apt",
			"Update package lists: sudo apt update",
			"Check repository configuration: cat /etc/apt/sources.list",
		},
		"permission denied": {
			"Check file/directory permissions: ls -la",
			"Use appropriate user permissions",
			"Try running with sudo if necessary",
		},
		"container not found": {
			"Verify container image exists: podman images",
			"Pull the container: podman pull <image>",
			"Check image reference format",
		},
		"out of disk space": {
			"Free up disk space: df -h",
			"Remove unnecessary files",
			"Use a different output directory",
		},
		"out of memory": {
			"Close other applications",
			"Add swap space if needed",
			"Use a system with more RAM",
		},
	}
}
