package monitoring

import (
	"testing"
	"time"

	"github.com/rcourtman/pulse-go-rewrite/pkg/pbs"
)

func TestConvertPBSSnapshots(t *testing.T) {
	t.Run("empty input returns empty slice", func(t *testing.T) {
		result := convertPBSSnapshots("pbs-1", "backup-store", "ns1", nil)
		if len(result) != 0 {
			t.Errorf("expected empty slice, got %d items", len(result))
		}

		result = convertPBSSnapshots("pbs-1", "backup-store", "ns1", []pbs.BackupSnapshot{})
		if len(result) != 0 {
			t.Errorf("expected empty slice, got %d items", len(result))
		}
	})

	t.Run("basic snapshot conversion", func(t *testing.T) {
		backupTime := int64(1700000000)
		snapshots := []pbs.BackupSnapshot{
			{
				BackupType: "vm",
				BackupID:   "100",
				BackupTime: backupTime,
				Size:       1024000,
				Protected:  true,
				Comment:    "Test backup",
				Owner:      "root@pam",
			},
		}

		result := convertPBSSnapshots("pbs-prod", "datastore1", "production", snapshots)

		if len(result) != 1 {
			t.Fatalf("expected 1 backup, got %d", len(result))
		}

		backup := result[0]
		expectedID := "pbs-pbs-prod-datastore1-production-vm-100-1700000000"
		if backup.ID != expectedID {
			t.Errorf("ID: expected %q, got %q", expectedID, backup.ID)
		}
		if backup.Instance != "pbs-prod" {
			t.Errorf("Instance: expected %q, got %q", "pbs-prod", backup.Instance)
		}
		if backup.Datastore != "datastore1" {
			t.Errorf("Datastore: expected %q, got %q", "datastore1", backup.Datastore)
		}
		if backup.Namespace != "production" {
			t.Errorf("Namespace: expected %q, got %q", "production", backup.Namespace)
		}
		if backup.BackupType != "vm" {
			t.Errorf("BackupType: expected %q, got %q", "vm", backup.BackupType)
		}
		if backup.VMID != "100" {
			t.Errorf("VMID: expected %q, got %q", "100", backup.VMID)
		}
		expectedTime := time.Unix(backupTime, 0)
		if !backup.BackupTime.Equal(expectedTime) {
			t.Errorf("BackupTime: expected %v, got %v", expectedTime, backup.BackupTime)
		}
		if backup.Size != 1024000 {
			t.Errorf("Size: expected %d, got %d", 1024000, backup.Size)
		}
		if !backup.Protected {
			t.Error("Protected: expected true")
		}
		if backup.Verified {
			t.Error("Verified: expected false (no verification data)")
		}
		if backup.Comment != "Test backup" {
			t.Errorf("Comment: expected %q, got %q", "Test backup", backup.Comment)
		}
		if backup.Owner != "root@pam" {
			t.Errorf("Owner: expected %q, got %q", "root@pam", backup.Owner)
		}
	})

	t.Run("files as string array", func(t *testing.T) {
		snapshots := []pbs.BackupSnapshot{
			{
				BackupType: "ct",
				BackupID:   "200",
				BackupTime: 1700000000,
				Files:      []interface{}{"file1.img", "file2.pxar", "file3.conf"},
			},
		}

		result := convertPBSSnapshots("pbs-1", "store", "", snapshots)

		if len(result[0].Files) != 3 {
			t.Fatalf("expected 3 files, got %d", len(result[0].Files))
		}
		if result[0].Files[0] != "file1.img" {
			t.Errorf("Files[0]: expected %q, got %q", "file1.img", result[0].Files[0])
		}
		if result[0].Files[1] != "file2.pxar" {
			t.Errorf("Files[1]: expected %q, got %q", "file2.pxar", result[0].Files[1])
		}
		if result[0].Files[2] != "file3.conf" {
			t.Errorf("Files[2]: expected %q, got %q", "file3.conf", result[0].Files[2])
		}
	})

	t.Run("files as object array with filename field", func(t *testing.T) {
		snapshots := []pbs.BackupSnapshot{
			{
				BackupType: "vm",
				BackupID:   "300",
				BackupTime: 1700000000,
				Files: []interface{}{
					map[string]interface{}{"filename": "disk-0.raw", "size": 10737418240},
					map[string]interface{}{"filename": "vm.conf", "size": 1024},
				},
			},
		}

		result := convertPBSSnapshots("pbs-1", "store", "", snapshots)

		if len(result[0].Files) != 2 {
			t.Fatalf("expected 2 files, got %d", len(result[0].Files))
		}
		if result[0].Files[0] != "disk-0.raw" {
			t.Errorf("Files[0]: expected %q, got %q", "disk-0.raw", result[0].Files[0])
		}
		if result[0].Files[1] != "vm.conf" {
			t.Errorf("Files[1]: expected %q, got %q", "vm.conf", result[0].Files[1])
		}
	})

	t.Run("files with missing filename field ignored", func(t *testing.T) {
		snapshots := []pbs.BackupSnapshot{
			{
				BackupType: "vm",
				BackupID:   "400",
				BackupTime: 1700000000,
				Files: []interface{}{
					map[string]interface{}{"filename": "valid.raw"},
					map[string]interface{}{"name": "invalid.raw"}, // Wrong field name
					map[string]interface{}{},                       // Empty object
				},
			},
		}

		result := convertPBSSnapshots("pbs-1", "store", "", snapshots)

		if len(result[0].Files) != 1 {
			t.Fatalf("expected 1 file (only valid one), got %d", len(result[0].Files))
		}
		if result[0].Files[0] != "valid.raw" {
			t.Errorf("Files[0]: expected %q, got %q", "valid.raw", result[0].Files[0])
		}
	})

	t.Run("verification as string ok", func(t *testing.T) {
		snapshots := []pbs.BackupSnapshot{
			{
				BackupType:   "vm",
				BackupID:     "500",
				BackupTime:   1700000000,
				Verification: "ok",
			},
		}

		result := convertPBSSnapshots("pbs-1", "store", "", snapshots)

		if !result[0].Verified {
			t.Error("Verified: expected true when verification is 'ok'")
		}
	})

	t.Run("verification as string not ok", func(t *testing.T) {
		snapshots := []pbs.BackupSnapshot{
			{
				BackupType:   "vm",
				BackupID:     "501",
				BackupTime:   1700000000,
				Verification: "failed",
			},
		}

		result := convertPBSSnapshots("pbs-1", "store", "", snapshots)

		if result[0].Verified {
			t.Error("Verified: expected false when verification is not 'ok'")
		}
	})

	t.Run("verification as object with state ok", func(t *testing.T) {
		snapshots := []pbs.BackupSnapshot{
			{
				BackupType: "vm",
				BackupID:   "600",
				BackupTime: 1700000000,
				Verification: map[string]interface{}{
					"state":    "ok",
					"upid":     "UPID:pbs:00001234",
					"snapshot": "2023-11-14T12:00:00Z",
				},
			},
		}

		result := convertPBSSnapshots("pbs-1", "store", "", snapshots)

		if !result[0].Verified {
			t.Error("Verified: expected true when verification.state is 'ok'")
		}
	})

	t.Run("verification as object with state failed", func(t *testing.T) {
		snapshots := []pbs.BackupSnapshot{
			{
				BackupType: "vm",
				BackupID:   "601",
				BackupTime: 1700000000,
				Verification: map[string]interface{}{
					"state": "failed",
					"upid":  "UPID:pbs:00005678",
				},
			},
		}

		result := convertPBSSnapshots("pbs-1", "store", "", snapshots)

		if result[0].Verified {
			t.Error("Verified: expected false when verification.state is 'failed'")
		}
	})

	t.Run("verification as object without state field", func(t *testing.T) {
		snapshots := []pbs.BackupSnapshot{
			{
				BackupType: "vm",
				BackupID:   "602",
				BackupTime: 1700000000,
				Verification: map[string]interface{}{
					"upid": "UPID:pbs:00009999",
				},
			},
		}

		result := convertPBSSnapshots("pbs-1", "store", "", snapshots)

		if result[0].Verified {
			t.Error("Verified: expected false when verification object has no state field")
		}
	})

	t.Run("multiple snapshots", func(t *testing.T) {
		snapshots := []pbs.BackupSnapshot{
			{
				BackupType: "vm",
				BackupID:   "100",
				BackupTime: 1700000000,
			},
			{
				BackupType: "ct",
				BackupID:   "200",
				BackupTime: 1700001000,
			},
			{
				BackupType: "vm",
				BackupID:   "100",
				BackupTime: 1700002000, // Same VM, different time
			},
		}

		result := convertPBSSnapshots("pbs-1", "store", "ns", snapshots)

		if len(result) != 3 {
			t.Fatalf("expected 3 backups, got %d", len(result))
		}

		// Verify each has unique ID
		ids := make(map[string]bool)
		for _, backup := range result {
			if ids[backup.ID] {
				t.Errorf("duplicate ID found: %s", backup.ID)
			}
			ids[backup.ID] = true
		}
	})

	t.Run("empty namespace in ID", func(t *testing.T) {
		snapshots := []pbs.BackupSnapshot{
			{
				BackupType: "vm",
				BackupID:   "100",
				BackupTime: 1700000000,
			},
		}

		result := convertPBSSnapshots("pbs-1", "store", "", snapshots)

		expectedID := "pbs-pbs-1-store--vm-100-1700000000"
		if result[0].ID != expectedID {
			t.Errorf("ID with empty namespace: expected %q, got %q", expectedID, result[0].ID)
		}
	})

	t.Run("container backup type", func(t *testing.T) {
		snapshots := []pbs.BackupSnapshot{
			{
				BackupType: "ct",
				BackupID:   "101",
				BackupTime: 1700000000,
				Size:       512000,
			},
		}

		result := convertPBSSnapshots("pbs-1", "store", "ns", snapshots)

		if result[0].BackupType != "ct" {
			t.Errorf("BackupType: expected %q, got %q", "ct", result[0].BackupType)
		}
	})
}
