package hpe_ilo_ahs

import (
	"bytes"
	"compress/gzip"
	"encoding/binary"
	"os"
	"path/filepath"
	"testing"

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

func TestDetectAHS(t *testing.T) {
	p := &Parser{}
	score := p.Detect([]parser.ExtractedFile{{
		Path:    "HPE_CZ2D1X0GS3_20260330.ahs",
		Content: makeAHSArchive(t, []ahsTestEntry{{Name: "CUST_INFO.DAT", Payload: []byte("x")}}),
	}})
	if score < 80 {
		t.Fatalf("expected high confidence detect, got %d", score)
	}
}

func TestParseAHSInventory(t *testing.T) {
	p := &Parser{}
	content := makeAHSArchive(t, []ahsTestEntry{
		{Name: "CUST_INFO.DAT", Payload: make([]byte, 16)},
		{Name: "0000088-2026-03-30.zbb", Payload: gzipBytes(t, []byte(sampleInventoryBlob()))},
		{Name: "bcert.pkg", Payload: []byte(sampleBCertBlob())},
	})

	result, err := p.Parse([]parser.ExtractedFile{{
		Path:    "HPE_CZ2D1X0GS3_20260330.ahs",
		Content: content,
	}})
	if err != nil {
		t.Fatalf("parse failed: %v", err)
	}
	if result.Hardware == nil {
		t.Fatalf("expected hardware section")
	}

	board := result.Hardware.BoardInfo
	if board.Manufacturer != "HPE" {
		t.Fatalf("unexpected board manufacturer: %q", board.Manufacturer)
	}
	if board.ProductName != "ProLiant DL380 Gen11" {
		t.Fatalf("unexpected board product: %q", board.ProductName)
	}
	if board.SerialNumber != "CZ2D1X0GS3" {
		t.Fatalf("unexpected board serial: %q", board.SerialNumber)
	}
	if board.PartNumber != "P52560-421" {
		t.Fatalf("unexpected board part number: %q", board.PartNumber)
	}

	if len(result.Hardware.CPUs) != 1 || result.Hardware.CPUs[0].Model != "Intel(R) Xeon(R) Gold 6444Y" {
		t.Fatalf("unexpected CPUs: %+v", result.Hardware.CPUs)
	}
	if len(result.Hardware.Memory) != 1 {
		t.Fatalf("expected one DIMM, got %d", len(result.Hardware.Memory))
	}
	if result.Hardware.Memory[0].PartNumber != "HMCG88AEBRA115N" {
		t.Fatalf("unexpected DIMM part number: %q", result.Hardware.Memory[0].PartNumber)
	}

	if len(result.Hardware.NetworkAdapters) != 2 {
		t.Fatalf("expected two network adapters, got %d", len(result.Hardware.NetworkAdapters))
	}
	if len(result.Hardware.PowerSupply) != 1 {
		t.Fatalf("expected one PSU, got %d", len(result.Hardware.PowerSupply))
	}
	if result.Hardware.PowerSupply[0].SerialNumber != "5XUWB0C4DJG4BV" {
		t.Fatalf("unexpected PSU serial: %q", result.Hardware.PowerSupply[0].SerialNumber)
	}
	if result.Hardware.PowerSupply[0].Firmware != "2.00" {
		t.Fatalf("unexpected PSU firmware: %q", result.Hardware.PowerSupply[0].Firmware)
	}

	if len(result.Hardware.Storage) != 1 {
		t.Fatalf("expected one physical drive, got %d", len(result.Hardware.Storage))
	}
	drive := result.Hardware.Storage[0]
	if drive.Model != "SAMSUNGMZ7L3480HCHQ-00A07" {
		t.Fatalf("unexpected drive model: %q", drive.Model)
	}
	if drive.SerialNumber != "S664NC0Y502720" {
		t.Fatalf("unexpected drive serial: %q", drive.SerialNumber)
	}
	if drive.SizeGB != 480 {
		t.Fatalf("unexpected drive size: %d", drive.SizeGB)
	}

	if len(result.Hardware.Firmware) == 0 {
		t.Fatalf("expected firmware inventory")
	}
	foundILO := false
	foundControllerFW := false
	foundNICFW := false
	foundBackplaneFW := false
	for _, item := range result.Hardware.Firmware {
		if item.DeviceName == "iLO 6" && item.Version == "v1.63p20" {
			foundILO = true
		}
		if item.DeviceName == "HPE MR408i-o Gen11" && item.Version == "52.26.3-5379" {
			foundControllerFW = true
		}
		if item.DeviceName == "BCM 5719 1Gb 4p BASE-T OCP Adptr" && item.Version == "20.28.41" {
			foundNICFW = true
		}
		if item.DeviceName == "8 SFF 24G x1NVMe/SAS UBM3 BC BP" && item.Version == "1.24" {
			foundBackplaneFW = true
		}
	}
	if !foundILO {
		t.Fatalf("expected iLO firmware entry")
	}
	if !foundControllerFW {
		t.Fatalf("expected controller firmware entry")
	}
	if !foundNICFW {
		t.Fatalf("expected broadcom firmware entry")
	}
	if !foundBackplaneFW {
		t.Fatalf("expected backplane firmware entry")
	}

	broadcomFound := false
	backplaneFound := false
	for _, nic := range result.Hardware.NetworkAdapters {
		if nic.SerialNumber == "1CH0150001" && nic.Firmware == "20.28.41" {
			broadcomFound = true
		}
	}
	for _, dev := range result.Hardware.Devices {
		if dev.DeviceClass == "storage_backplane" && dev.Firmware == "1.24" {
			backplaneFound = true
		}
	}
	if !broadcomFound {
		t.Fatalf("expected broadcom adapter firmware to be enriched")
	}
	if !backplaneFound {
		t.Fatalf("expected backplane canonical device")
	}

	if len(result.Hardware.Devices) < 6 {
		t.Fatalf("expected canonical devices, got %d", len(result.Hardware.Devices))
	}
	if len(result.Events) == 0 {
		t.Fatalf("expected parsed events")
	}
}

func TestParseExampleAHS(t *testing.T) {
	path := filepath.Join("..", "..", "..", "..", "example", "HPE_CZ2D1X0GS3_20260330.ahs")
	content, err := os.ReadFile(path)
	if err != nil {
		t.Skipf("example fixture unavailable: %v", err)
	}

	p := &Parser{}
	result, err := p.Parse([]parser.ExtractedFile{{
		Path:    filepath.Base(path),
		Content: content,
	}})
	if err != nil {
		t.Fatalf("parse example failed: %v", err)
	}
	if result.Hardware == nil {
		t.Fatalf("expected hardware section")
	}

	board := result.Hardware.BoardInfo
	if board.ProductName != "ProLiant DL380 Gen11" {
		t.Fatalf("unexpected board product: %q", board.ProductName)
	}
	if board.SerialNumber != "CZ2D1X0GS3" {
		t.Fatalf("unexpected board serial: %q", board.SerialNumber)
	}

	if len(result.Hardware.Storage) < 2 {
		t.Fatalf("expected at least two drives, got %d", len(result.Hardware.Storage))
	}
	if len(result.Hardware.PowerSupply) != 2 {
		t.Fatalf("expected exactly two PSUs, got %d: %+v", len(result.Hardware.PowerSupply), result.Hardware.PowerSupply)
	}

	foundController := false
	foundBackplaneFW := false
	foundNICFW := false
	for _, device := range result.Hardware.Devices {
		if device.Model == "HPE MR408i-o Gen11" && device.SerialNumber == "PXSFQ0BBIJY3B3" {
			foundController = true
		}
		if device.DeviceClass == "storage_backplane" && device.Firmware == "1.24" {
			foundBackplaneFW = true
		}
	}
	if !foundController {
		t.Fatalf("expected MR408i-o controller in canonical devices")
	}
	for _, fw := range result.Hardware.Firmware {
		if fw.DeviceName == "BCM 5719 1Gb 4p BASE-T OCP Adptr" && fw.Version == "20.28.41" {
			foundNICFW = true
		}
	}
	if !foundBackplaneFW {
		t.Fatalf("expected backplane device in canonical devices")
	}
	if !foundNICFW {
		t.Fatalf("expected broadcom firmware from bcert/pkg lockdown")
	}
}

type ahsTestEntry struct {
	Name    string
	Payload []byte
	Flag    uint32
}

func makeAHSArchive(t *testing.T, entries []ahsTestEntry) []byte {
	t.Helper()

	var buf bytes.Buffer
	for _, entry := range entries {
		header := make([]byte, ahsHeaderSize)
		copy(header[:4], []byte("ABJR"))
		binary.LittleEndian.PutUint16(header[4:6], 0x0300)
		binary.LittleEndian.PutUint16(header[6:8], 0x0002)
		binary.LittleEndian.PutUint32(header[8:12], uint32(len(entry.Payload)))
		flag := entry.Flag
		if flag == 0 {
			flag = 0x80000002
			if len(entry.Payload) >= 2 && entry.Payload[0] == 0x1f && entry.Payload[1] == 0x8b {
				flag = 0x80000001
			}
		}
		binary.LittleEndian.PutUint32(header[16:20], flag)
		copy(header[20:52], []byte(entry.Name))
		buf.Write(header)
		buf.Write(entry.Payload)
	}
	return buf.Bytes()
}

func gzipBytes(t *testing.T, payload []byte) []byte {
	t.Helper()

	var buf bytes.Buffer
	zw := gzip.NewWriter(&buf)
	if _, err := zw.Write(payload); err != nil {
		t.Fatalf("gzip payload: %v", err)
	}
	if err := zw.Close(); err != nil {
		t.Fatalf("close gzip writer: %v", err)
	}
	return buf.Bytes()
}

func sampleInventoryBlob() string {
	return stringsJoin(
		"iLO 6 v1.63p20 built on Sep 13 2024",
		"HPE",
		"ProLiant DL380 Gen11",
		"CZ2D1X0GS3",
		"P52560-421",
		"Proc 1",
		"Intel(R) Corporation",
		"Intel(R) Xeon(R) Gold 6444Y",
		"PROC 1 DIMM 3",
		"Hynix",
		"HMCG88AEBRA115N",
		"2B5F92C6",
		"Power Supply 1",
		"5XUWB0C4DJG4BV",
		"P03178-B21",
		"PciRoot(0x1)/Pci(0x5,0x0)/Pci(0x0,0x0)",
		"NIC.Slot.1.1",
		"Network Controller",
		"Slot 1",
		"MCX512A-ACAT",
		"MT2230478382",
		"PciRoot(0x3)/Pci(0x1,0x0)/Pci(0x0,0x0)",
		"OCP.Slot.15.1",
		"Broadcom NetXtreme Gigabit Ethernet - NIC",
		"OCP Slot 15",
		"P51183-001",
		"1CH0150001",
		"20.28.41",
		"System ROM",
		"v2.22 (06/19/2024)",
		"03/30/2026 09:47:33",
		"iLO network link down.",
		`{"@odata.id":"/redfish/v1/Systems/1/Storage/DE00A000/Controllers/0","@odata.type":"#StorageController.v1_7_0.StorageController","Id":"0","Name":"HPE MR408i-o Gen11","FirmwareVersion":"52.26.3-5379","Manufacturer":"HPE","Model":"HPE MR408i-o Gen11","PartNumber":"P58543-001","SKU":"P58335-B21","SerialNumber":"PXSFQ0BBIJY3B3","Status":{"State":"Enabled","Health":"OK"},"Location":{"PartLocation":{"ServiceLabel":"Slot=14","LocationType":"Slot","LocationOrdinalValue":14}},"PCIeInterface":{"PCIeType":"Gen4","LanesInUse":8}}`,
		`{"@odata.id":"/redfish/v1/Fabrics/DE00A000","@odata.type":"#Fabric.v1_3_0.Fabric","Id":"DE00A000","Name":"8 SFF 24G x1NVMe/SAS UBM3 BC BP","FabricType":"MultiProtocol"}`,
		`{"@odata.id":"/redfish/v1/Fabrics/DE00A000/Switches/1","@odata.type":"#Switch.v1_9_1.Switch","Id":"1","Name":"Direct Attached","Model":"UBM3","FirmwareVersion":"1.24","SupportedProtocols":["SAS","SATA","NVMe"],"SwitchType":"MultiProtocol","Status":{"State":"Enabled","Health":"OK"}}`,
		`{"@odata.id":"/redfish/v1/Chassis/DE00A000/Drives/0","@odata.type":"#Drive.v1_17_0.Drive","Id":"0","Name":"480GB 6G SATA SSD","Status":{"State":"StandbyOffline","Health":"OK"},"PhysicalLocation":{"PartLocation":{"ServiceLabel":"Slot=14:Port=1:Box=3:Bay=1","LocationType":"Bay","LocationOrdinalValue":1}},"CapacityBytes":480103981056,"MediaType":"SSD","Model":"SAMSUNGMZ7L3480HCHQ-00A07","Protocol":"SATA","Revision":"JXTC604Q","SerialNumber":"S664NC0Y502720","PredictedMediaLifeLeftPercent":100}`,
		`{"@odata.id":"/redfish/v1/Chassis/DE00A000/Drives/64515","@odata.type":"#Drive.v1_17_0.Drive","Id":"64515","Name":"Empty Bay","Status":{"State":"Absent","Health":"OK"}}`,
	)
}

func sampleBCertBlob() string {
	return `<BC><MfgRecord><PowerSupplySlot id="0"><Present>Yes</Present><SerialNumber>5XUWB0C4DJG4BV</SerialNumber><FirmwareVersion>2.00</FirmwareVersion><SparePartNumber>P44412-001</SparePartNumber></PowerSupplySlot><FirmwareLockdown><SystemProgrammableLogicDevice>0x12</SystemProgrammableLogicDevice><ServerPlatformServicesSPSFirmware>6.1.4.47</ServerPlatformServicesSPSFirmware><STMicroGen11TPM>1.512</STMicroGen11TPM><HPEMR408i-oGen11>52.26.3-5379</HPEMR408i-oGen11><UBM3>UBM3/1.24</UBM3><BCM57191Gb4pBASE-TOCP3>20.28.41</BCM57191Gb4pBASE-TOCP3></FirmwareLockdown></MfgRecord></BC>`
}

func stringsJoin(parts ...string) string {
	return string(bytes.Join(func() [][]byte {
		out := make([][]byte, 0, len(parts))
		for _, part := range parts {
			out = append(out, []byte(part))
		}
		return out
	}(), []byte{0}))
}
