package inspur

import (
	"regexp"
	"sort"
	"strconv"
	"strings"

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

var reFaultGPU = regexp.MustCompile(`\bF_GPU(\d+)\b`)

func applyGPUStatusFromEvents(hw *models.HardwareConfig, events []models.Event) {
	if hw == nil || len(hw.GPUs) == 0 {
		return
	}

	gpuByIndex := make(map[int]*models.GPU)
	for i := range hw.GPUs {
		gpu := &hw.GPUs[i]
		idx, ok := extractLogicalGPUIndex(gpu.Slot)
		if !ok {
			continue
		}
		gpuByIndex[idx] = gpu
		gpu.StatusHistory = nil
		gpu.ErrorDescription = ""
	}

	relevantEvents := make([]models.Event, 0)
	for _, e := range events {
		if !isGPUFaultEvent(e) || len(extractFaultyGPUSet(e.Description)) == 0 {
			continue
		}
		relevantEvents = append(relevantEvents, e)
	}

	if len(relevantEvents) == 0 {
		for _, gpu := range gpuByIndex {
			if strings.TrimSpace(gpu.Status) == "" {
				gpu.Status = "OK"
			}
		}
		return
	}

	sort.Slice(relevantEvents, func(i, j int) bool {
		return relevantEvents[i].Timestamp.Before(relevantEvents[j].Timestamp)
	})

	currentStatus := make(map[int]string, len(gpuByIndex))
	lastCriticalDetails := make(map[int]string, len(gpuByIndex))
	for idx := range gpuByIndex {
		currentStatus[idx] = "OK"
	}

	for _, e := range relevantEvents {
		faultySet := extractFaultyGPUSet(e.Description)
		for idx, gpu := range gpuByIndex {
			newStatus := "OK"
			if faultySet[idx] {
				newStatus = "Critical"
				lastCriticalDetails[idx] = strings.TrimSpace(e.Description)
			}

			if currentStatus[idx] != newStatus {
				gpu.StatusHistory = append(gpu.StatusHistory, models.StatusHistoryEntry{
					Status:    newStatus,
					ChangedAt: e.Timestamp,
					Details:   strings.TrimSpace(e.Description),
				})
				ts := e.Timestamp
				gpu.StatusChangedAt = &ts
				currentStatus[idx] = newStatus
			}

			ts := e.Timestamp
			gpu.StatusCheckedAt = &ts
		}
	}

	for idx, gpu := range gpuByIndex {
		gpu.Status = currentStatus[idx]
		if gpu.Status == "Critical" {
			gpu.ErrorDescription = lastCriticalDetails[idx]
		} else {
			gpu.ErrorDescription = ""
		}
		if gpu.StatusCheckedAt == nil && strings.TrimSpace(gpu.Status) == "" {
			gpu.Status = "OK"
		}
	}
}

func extractFaultyGPUSet(description string) map[int]bool {
	faulty := make(map[int]bool)
	matches := reFaultGPU.FindAllStringSubmatch(description, -1)
	for _, m := range matches {
		if len(m) < 2 {
			continue
		}
		idx, err := strconv.Atoi(m[1])
		if err == nil && idx >= 0 {
			faulty[idx] = true
		}
	}
	return faulty
}

func isGPUFaultEvent(e models.Event) bool {
	desc := strings.ToLower(e.Description)
	if strings.Contains(desc, "bios miss f_gpu") {
		return true
	}
	return strings.EqualFold(strings.TrimSpace(e.ID), "17FFB002")
}
