package unraid

import (
	"testing"

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

func TestDetect(t *testing.T) {
	tests := []struct {
		name       string
		files      []parser.ExtractedFile
		wantMin    int
		wantMax    int
		shouldFind bool
	}{
		{
			name: "typical unraid diagnostics",
			files: []parser.ExtractedFile{
				{
					Path:    "box3-diagnostics-20260205-2333/unraid-7.2.0.txt",
					Content: []byte("7.2.0\n"),
				},
				{
					Path:    "box3-diagnostics-20260205-2333/system/vars.txt",
					Content: []byte("[parity] => Array\n[disk1] => Array\n"),
				},
			},
			wantMin:    50,
			wantMax:    100,
			shouldFind: true,
		},
		{
			name: "unraid with kernel marker",
			files: []parser.ExtractedFile{
				{
					Path:    "diagnostics/system/lscpu.txt",
					Content: []byte("Unraid kernel build 6.12.54"),
				},
			},
			wantMin:    50,
			wantMax:    100,
			shouldFind: true,
		},
		{
			name: "not unraid",
			files: []parser.ExtractedFile{
				{
					Path:    "some/random/file.txt",
					Content: []byte("just some random content"),
				},
			},
			wantMin:    0,
			wantMax:    0,
			shouldFind: false,
		},
	}

	p := &Parser{}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := p.Detect(tt.files)

			if tt.shouldFind && got < tt.wantMin {
				t.Errorf("Detect() = %v, want at least %v", got, tt.wantMin)
			}

			if got > tt.wantMax {
				t.Errorf("Detect() = %v, want at most %v", got, tt.wantMax)
			}

			if !tt.shouldFind && got > 0 {
				t.Errorf("Detect() = %v, want 0 (should not detect)", got)
			}
		})
	}
}

func TestParse_Version(t *testing.T) {
	files := []parser.ExtractedFile{
		{
			Path:    "unraid-7.2.0.txt",
			Content: []byte("7.2.0\n"),
		},
	}

	p := &Parser{}
	result, err := p.Parse(files)

	if err != nil {
		t.Fatalf("Parse() error = %v", err)
	}

	if len(result.Hardware.Firmware) == 0 {
		t.Fatal("expected firmware info")
	}

	fw := result.Hardware.Firmware[0]
	if fw.DeviceName != "Unraid OS" {
		t.Errorf("DeviceName = %v, want 'Unraid OS'", fw.DeviceName)
	}

	if fw.Version != "7.2.0" {
		t.Errorf("Version = %v, want '7.2.0'", fw.Version)
	}
}

func TestParse_CPU(t *testing.T) {
	lscpuContent := `Architecture:                            x86_64
CPU op-mode(s):                          32-bit, 64-bit
CPU(s):                                  16
Model name:                              Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz
Core(s) per socket:                      8
Socket(s):                               1
CPU max MHz:                             3400.0000
`

	files := []parser.ExtractedFile{
		{
			Path:    "diagnostics/system/lscpu.txt",
			Content: []byte(lscpuContent),
		},
	}

	p := &Parser{}
	result, err := p.Parse(files)

	if err != nil {
		t.Fatalf("Parse() error = %v", err)
	}

	if len(result.Hardware.CPUs) == 0 {
		t.Fatal("expected CPU info")
	}

	cpu := result.Hardware.CPUs[0]
	if cpu.Model != "Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz" {
		t.Errorf("Model = %v", cpu.Model)
	}

	if cpu.Cores != 8 {
		t.Errorf("Cores = %v, want 8", cpu.Cores)
	}

	if cpu.Threads != 16 {
		t.Errorf("Threads = %v, want 16", cpu.Threads)
	}

	if cpu.FrequencyMHz != 3400 {
		t.Errorf("FrequencyMHz = %v, want 3400", cpu.FrequencyMHz)
	}
}

func TestParse_Memory(t *testing.T) {
	memContent := `               total        used        free      shared  buff/cache   available
Mem:            50Gi        11Gi       1.4Gi       565Mi        39Gi        39Gi
Swap:             0B          0B          0B
Total:          50Gi        11Gi       1.4Gi
`

	files := []parser.ExtractedFile{
		{
			Path:    "diagnostics/system/memory.txt",
			Content: []byte(memContent),
		},
	}

	p := &Parser{}
	result, err := p.Parse(files)

	if err != nil {
		t.Fatalf("Parse() error = %v", err)
	}

	if len(result.Hardware.Memory) == 0 {
		t.Fatal("expected memory info")
	}

	mem := result.Hardware.Memory[0]
	expectedSizeMB := 50 * 1024 // 50 GiB in MB

	if mem.SizeMB != expectedSizeMB {
		t.Errorf("SizeMB = %v, want %v", mem.SizeMB, expectedSizeMB)
	}

	if mem.Type != "DRAM" {
		t.Errorf("Type = %v, want 'DRAM'", mem.Type)
	}
}

func TestParse_SMART(t *testing.T) {
	smartContent := `smartctl 7.5 2025-04-30 r5714 [x86_64-linux-6.12.54-Unraid] (local build)
Copyright (C) 2002-25, Bruce Allen, Christian Franke, www.smartmontools.org

=== START OF INFORMATION SECTION ===
Device Model:     ST4000NM000B-2TF100
Serial Number:    WX103EC9
LU WWN Device Id: 5 000c50 0ed59db60
Firmware Version: TNA1
User Capacity:    4,000,787,030,016 bytes [4.00 TB]
Sector Size:      512 bytes logical/physical
Rotation Rate:    7200 rpm
Form Factor:      3.5 inches
SATA Version is:  SATA 3.3, 6.0 Gb/s (current: 6.0 Gb/s)

=== START OF READ SMART DATA SECTION ===
SMART overall-health self-assessment test result: PASSED
`

	files := []parser.ExtractedFile{
		{
			Path:    "diagnostics/smart/ST4000NM000B-2TF100_WX103EC9-20260205-2333 disk1 (sdi).txt",
			Content: []byte(smartContent),
		},
	}

	p := &Parser{}
	result, err := p.Parse(files)

	if err != nil {
		t.Fatalf("Parse() error = %v", err)
	}

	if len(result.Hardware.Storage) == 0 {
		t.Fatal("expected storage info")
	}

	disk := result.Hardware.Storage[0]

	if disk.Model != "ST4000NM000B-2TF100" {
		t.Errorf("Model = %v, want 'ST4000NM000B-2TF100'", disk.Model)
	}

	if disk.SerialNumber != "WX103EC9" {
		t.Errorf("SerialNumber = %v, want 'WX103EC9'", disk.SerialNumber)
	}

	if disk.Firmware != "TNA1" {
		t.Errorf("Firmware = %v, want 'TNA1'", disk.Firmware)
	}

	if disk.SizeGB != 4000 {
		t.Errorf("SizeGB = %v, want 4000", disk.SizeGB)
	}

	if disk.Type != "hdd" {
		t.Errorf("Type = %v, want 'hdd'", disk.Type)
	}

	// Check that no health warnings were generated (PASSED health)
	healthWarnings := 0
	for _, event := range result.Events {
		if event.EventType == "Disk Health" && event.Severity == "warning" {
			healthWarnings++
		}
	}
	if healthWarnings != 0 {
		t.Errorf("Expected no health warnings for PASSED disk, got %v", healthWarnings)
	}
}

func TestParser_Metadata(t *testing.T) {
	p := &Parser{}

	if p.Name() != "Unraid Parser" {
		t.Errorf("Name() = %v, want 'Unraid Parser'", p.Name())
	}

	if p.Vendor() != "unraid" {
		t.Errorf("Vendor() = %v, want 'unraid'", p.Vendor())
	}

	if p.Version() == "" {
		t.Error("Version() should not be empty")
	}
}
