package nvidia_bug_report

import (
	"bufio"
	"strconv"
	"strings"
	"time"

	"git.mchus.pro/mchus/logpile/internal/models"
)

// parseMemoryModules extracts memory module information from dmidecode output
func parseMemoryModules(content string, result *models.AnalysisResult) {
	scanner := bufio.NewScanner(strings.NewReader(content))

	var currentModule *models.MemoryDIMM
	inMemoryDevice := false

	for scanner.Scan() {
		line := scanner.Text()
		trimmed := strings.TrimSpace(line)

		// Start of Memory Device section
		if strings.Contains(trimmed, "Memory Device") && !strings.Contains(trimmed, "Array") {
			inMemoryDevice = true
			currentModule = &models.MemoryDIMM{
				Present: true,
			}
			continue
		}

		// End of current section (empty line or new section)
		if inMemoryDevice && (trimmed == "" || strings.HasPrefix(trimmed, "Handle ")) {
			// Save module if it has valid data
			if currentModule != nil && currentModule.Slot != "" && currentModule.SizeMB > 0 {
				result.Hardware.Memory = append(result.Hardware.Memory, *currentModule)
			}
			inMemoryDevice = false
			currentModule = nil
			continue
		}

		// Parse fields within Memory Device section
		if inMemoryDevice && currentModule != nil && strings.Contains(line, ":") {
			parts := strings.SplitN(trimmed, ":", 2)
			if len(parts) != 2 {
				continue
			}

			field := strings.TrimSpace(parts[0])
			value := strings.TrimSpace(parts[1])

			if value == "" || value == "Not Specified" || value == "Unknown" || value == "NO DIMM" {
				continue
			}

			switch field {
			case "Size":
				// Parse size like "64 GB" or "32768 MB"
				currentModule.SizeMB = parseMemorySize(value)
			case "Locator":
				currentModule.Slot = value
				currentModule.Location = value
			case "Bank Locator":
				// Store in location if slot is empty
				if currentModule.Location == "" {
					currentModule.Location = value
				}
			case "Type":
				currentModule.Type = value
			case "Type Detail":
				currentModule.Technology = value
			case "Speed":
				// Parse speed like "5600 MT/s"
				currentModule.MaxSpeedMHz = parseMemorySpeed(value)
			case "Configured Memory Speed":
				currentModule.CurrentSpeedMHz = parseMemorySpeed(value)
			case "Manufacturer":
				currentModule.Manufacturer = value
			case "Serial Number":
				currentModule.SerialNumber = value
			case "Part Number":
				currentModule.PartNumber = strings.TrimSpace(value)
			case "Rank":
				// Parse rank
				if rank, err := strconv.Atoi(value); err == nil {
					currentModule.Ranks = rank
				}
			}
		}
	}

	// Save last module if exists
	if currentModule != nil && currentModule.Slot != "" && currentModule.SizeMB > 0 {
		result.Hardware.Memory = append(result.Hardware.Memory, *currentModule)
	}

	// Create event for memory summary
	if len(result.Hardware.Memory) > 0 {
		totalMemoryGB := 0
		for _, mem := range result.Hardware.Memory {
			totalMemoryGB += mem.SizeMB / 1024
		}

		result.Events = append(result.Events, models.Event{
			Timestamp:   time.Now(),
			Source:      "DMI",
			EventType:   "Memory Configuration",
			Description: "Memory modules detected",
			Severity:    models.SeverityInfo,
			RawData:     formatMemorySummary(result.Hardware.Memory, totalMemoryGB),
		})
	}
}

// parseMemorySize parses memory size strings like "64 GB" or "32768 MB"
func parseMemorySize(sizeStr string) int {
	parts := strings.Fields(sizeStr)
	if len(parts) < 2 {
		return 0
	}

	size, err := strconv.Atoi(parts[0])
	if err != nil {
		return 0
	}

	unit := strings.ToUpper(parts[1])
	switch unit {
	case "GB":
		return size * 1024
	case "MB":
		return size
	case "TB":
		return size * 1024 * 1024
	default:
		return 0
	}
}

// parseMemorySpeed parses speed strings like "5600 MT/s" or "4400 MHz"
func parseMemorySpeed(speedStr string) int {
	parts := strings.Fields(speedStr)
	if len(parts) < 1 {
		return 0
	}

	speed, err := strconv.Atoi(parts[0])
	if err != nil {
		return 0
	}

	return speed
}

// formatMemorySummary creates a summary string for memory modules
func formatMemorySummary(modules []models.MemoryDIMM, totalGB int) string {
	if len(modules) == 0 {
		return ""
	}

	// Group by manufacturer
	manufacturerCount := make(map[string]int)
	for _, mem := range modules {
		if mem.Manufacturer != "" {
			manufacturerCount[mem.Manufacturer]++
		}
	}

	summary := ""
	for mfr, count := range manufacturerCount {
		if summary != "" {
			summary += ", "
		}
		summary += mfr + ": " + strconv.Itoa(count) + " modules"
	}

	if summary == "" {
		summary = strconv.Itoa(len(modules)) + " modules"
	}

	return summary + ", Total: " + strconv.Itoa(totalGB) + " GB"
}
