package nvidia

import (
	"os"
	"path/filepath"
	"strings"
	"testing"

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

func TestParseInventoryLog(t *testing.T) {
	// Test with the real archive
	archivePath := filepath.Join("../../../../example", "A514359X5A09844_logs-20260115-151707.tar")

	// Check if file exists
	if _, err := os.Stat(archivePath); os.IsNotExist(err) {
		t.Skip("Test archive not found, skipping test")
	}

	// Extract files from archive
	files, err := parser.ExtractArchive(archivePath)
	if err != nil {
		t.Fatalf("Failed to extract archive: %v", err)
	}

	// Find inventory/output.log
	var inventoryLog *parser.ExtractedFile
	for _, f := range files {
		if strings.Contains(f.Path, "inventory/output.log") {
			inventoryLog = &f
			break
		}
	}

	if inventoryLog == nil {
		t.Fatal("inventory/output.log not found")
	}

	content := string(inventoryLog.Content)

	// Test devname regex - this extracts both slot mapping and serial numbers
	t.Log("Testing devname extraction:")
	lines := strings.Split(content, "\n")
	serialCount := 0
	for i, line := range lines {
		if strings.Contains(line, "devname=") && strings.Contains(line, "fieldiag") {
			t.Logf("Line %d: Found fieldiag command", i)
			matches := devnameRegex.FindAllStringSubmatch(line, -1)
			t.Logf("  Found %d devname matches", len(matches))
			for _, match := range matches {
				if len(match) == 3 {
					pciBDF := match[1]
					slotName := match[2]
					t.Logf("    PCI: %s -> Slot: %s", pciBDF, slotName)

					// Extract serial number from slot name
					if strings.HasPrefix(slotName, "SXM") {
						parts := strings.Split(slotName, "_")
						if len(parts) == 3 && parts[1] == "SN" {
							serial := parts[2]
							t.Logf("      Serial: %s", serial)
							serialCount++
						}
					}
				}
			}
			break
		}
	}
	t.Logf("\nTotal GPU serials extracted: %d", serialCount)

	if serialCount == 0 {
		t.Error("Expected to find GPU serial numbers, but found none")
	}
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func TestParseInventoryLog_AssignsNVSwitchSerialByBDF(t *testing.T) {
	content := []byte(`
$ lspci -vvvs 0000:05:00.0
05:00.0 Bridge: NVIDIA Corporation Device 22a3 (rev a1)
	Capabilities: [2f0 v1] Device Serial Number 99-d3-61-c8-ac-2d-b0-48

/tmp/fieldiag devname=0000:ba:00.0,SXM5_SN_1653925025497 fieldiag
`)

	result := &models.AnalysisResult{
		Hardware: &models.HardwareConfig{
			GPUs: []models.GPU{
				{
					Slot:         "GPUSXM5",
					BDF:          "0000:ba:00.0",
					SerialNumber: "",
				},
			},
			PCIeDevices: []models.PCIeDevice{
				{
					Slot:         "NVSWITCH0",
					BDF:          "0000:05:00.0",
					SerialNumber: "",
				},
			},
		},
	}

	if err := ParseInventoryLog(content, result); err != nil {
		t.Fatalf("ParseInventoryLog failed: %v", err)
	}

	if got := result.Hardware.PCIeDevices[0].SerialNumber; got != "99-d3-61-c8-ac-2d-b0-48" {
		t.Fatalf("expected NVSwitch serial 99-d3-61-c8-ac-2d-b0-48, got %q", got)
	}

	// GPU serial should come from fieldiag devname mapping.
	if got := result.Hardware.GPUs[0].SerialNumber; got != "1653925025497" {
		t.Fatalf("expected GPU serial 1653925025497, got %q", got)
	}
}
