package inventory

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

func TestLoadAndFindNodeBranches(t *testing.T) {
	dir := t.TempDir()
	path := filepath.Join(dir, "inventory.yaml")
	if err := os.WriteFile(path, []byte(`
classes:
  - name: ${CLASS}
    arch: arm64
    os: armbian
    image: file:///tmp/base.img
nodes:
  - name: node1
    class: ${CLASS}
    hostname: node1
    k3s_role: agent
`), 0o644); err != nil {
		t.Fatal(err)
	}
	t.Setenv("CLASS", "rpi4")
	inv, err := Load(path)
	if err != nil {
		t.Fatalf("Load: %v", err)
	}
	if _, _, err := inv.FindNode("missing"); err == nil {
		t.Fatal("expected missing node error")
	}
	if _, cls, err := inv.FindNode("node1"); err != nil || cls == nil {
		t.Fatalf("expected class lookup for node1, got class=%#v err=%v", cls, err)
	}
}

func TestLoadReportsReadFailures(t *testing.T) {
	if _, err := Load(filepath.Join(t.TempDir(), "missing.yaml")); err == nil {
		t.Fatal("expected missing inventory file to fail")
	}
}

func TestLoadExpandsOptionalCollections(t *testing.T) {
	t.Setenv("CLASS_NAME", "rpi5")
	t.Setenv("CLASS_LABEL_VALUE", "worker")
	t.Setenv("CLASS_TAINT", "special=true:NoSchedule")
	t.Setenv("NODE_LABEL_VALUE", "maintenance")
	t.Setenv("NODE_TAINT", "flash=true:NoSchedule")
	t.Setenv("SSH_KEY", "ssh-ed25519 AAA")
	t.Setenv("EMPTY_VALUE", "")
	t.Setenv("DISK_MOUNT", "/var/lib/longhorn")
	t.Setenv("DISK_UUID", "uuid-1")
	t.Setenv("DISK_FS", "ext4")
	t.Setenv("USB_BIND", "/var/lib/rancher")

	path := filepath.Join(t.TempDir(), "inventory.yaml")
	if err := os.WriteFile(path, []byte(`
classes:
  - name: ${CLASS_NAME}
    arch: arm64
    os: armbian
    image: file:///tmp/rpi5.img
    default_labels:
      role: ${CLASS_LABEL_VALUE}
    default_taints:
      - ${CLASS_TAINT}
nodes:
  - name: titan-18
    class: ${CLASS_NAME}
    hostname: titan-18
    ip: 192.168.22.18
    k3s_role: agent
    labels:
      purpose: ${NODE_LABEL_VALUE}
    taints:
      - ${NODE_TAINT}
    ssh_authorized_keys:
      - "  ${SSH_KEY}  "
      - ${EMPTY_VALUE}
    longhorn_disks:
      - mountpoint: ${DISK_MOUNT}
        uuid: ${DISK_UUID}
        fs: ${DISK_FS}
    usb_scratch:
      mountpoint: /mnt/usb
      bind_targets:
        - ${USB_BIND}
        - ${EMPTY_VALUE}
`), 0o644); err != nil {
		t.Fatal(err)
	}

	inv, err := Load(path)
	if err != nil {
		t.Fatalf("Load: %v", err)
	}
	if inv.Classes[0].DefaultLabels["role"] != "worker" || inv.Classes[0].DefaultTaints[0] != "special=true:NoSchedule" {
		t.Fatalf("class defaults not expanded: %#v", inv.Classes[0])
	}
	node := inv.Nodes[0]
	if node.Labels["purpose"] != "maintenance" || node.Taints[0] != "flash=true:NoSchedule" {
		t.Fatalf("node labels/taints not expanded: %#v", node)
	}
	if len(node.SSHAuthorized) != 1 || node.SSHAuthorized[0] != "ssh-ed25519 AAA" {
		t.Fatalf("ssh keys not trimmed/filtered: %#v", node.SSHAuthorized)
	}
	if len(node.LonghornDisks) != 1 || node.LonghornDisks[0].Mountpoint != "/var/lib/longhorn" || node.LonghornDisks[0].UUID != "uuid-1" || node.LonghornDisks[0].FS != "ext4" {
		t.Fatalf("longhorn disk not expanded: %#v", node.LonghornDisks)
	}
	if node.USBScratch == nil || len(node.USBScratch.BindTargets) != 1 || node.USBScratch.BindTargets[0] != "/var/lib/rancher" {
		t.Fatalf("usb bind targets not filtered: %#v", node.USBScratch)
	}
}
