package alerts

import (
	"testing"
	"time"
)

func TestGetTimeThresholdMappings(t *testing.T) {
	manager := NewManager()

	manager.mu.Lock()
	manager.config.TimeThresholds = map[string]int{
		"guest":   300,
		"node":    120,
		"storage": 45,
		"pbs":     90,
	}
	manager.config.TimeThreshold = 15
	manager.mu.Unlock()

	testCases := []struct {
		resourceType string
		expected     int
	}{
		{"VM", 300},
		{"Container", 300},
		{"ct", 300},
		{"guest", 300},
		{"qemu", 300},
		{"lxc", 300},
		{"Node", 120},
		{"storage", 45},
		{"PBS", 90},
		{"UNKNOWN", 15},
	}

	for _, tc := range testCases {
		if got := manager.getTimeThreshold("", tc.resourceType, "cpu"); got != tc.expected {
			t.Errorf("getTimeThreshold(%q, \"cpu\") = %d, want %d", tc.resourceType, got, tc.expected)
		}
	}
}

func TestGetTimeThresholdMetricOverrides(t *testing.T) {
	manager := NewManager()

	manager.mu.Lock()
	manager.config.TimeThreshold = 15
	manager.config.TimeThresholds = map[string]int{
		"guest":   30,
		"node":    60,
		"storage": 90,
	}
	manager.config.MetricTimeThresholds = map[string]map[string]int{
		"guest": {
			"cpu": 5,
		},
		"node": {
			"temperature": 120,
		},
		"all": {
			"default": 20,
		},
	}
	manager.mu.Unlock()

	cases := []struct {
		resourceID   string
		resourceType string
		metricType   string
		expected     int
	}{
		{"vm-resource", "VM", "cpu", 5},             // guest metric override
		{"vm-resource", "VM", "memory", 30},         // falls back to guest type delay
		{"node-1", "Node", "temperature", 120},      // node metric override
		{"node-1", "Node", "cpu", 60},               // node type delay
		{"storage-1", "storage", "usage", 90},       // storage type delay
		{"unknown", "unknown", "cpu", 20},           // global default metric override
		{"unknown", "unknown", "disk", 20},
	}

	for _, tc := range cases {
		if got := manager.getTimeThreshold(tc.resourceID, tc.resourceType, tc.metricType); got != tc.expected {
			t.Errorf("getTimeThreshold(%q, %q, %q) = %d, want %d", tc.resourceID, tc.resourceType, tc.metricType, got, tc.expected)
		}
	}
}

func TestCheckMetricUsesPendingStartTime(t *testing.T) {
	manager := NewManager()

	manager.mu.Lock()
	manager.config.TimeThresholds["guest"] = 2
	manager.mu.Unlock()

	threshold := &HysteresisThreshold{Trigger: 80, Clear: 75}

	// First exceedance should start tracking and not create an alert immediately.
	manager.checkMetric("guest-123", "test-vm", "node1", "qemu/123", "VM", "cpu", 90, threshold, nil)

	manager.mu.Lock()
	if len(manager.activeAlerts) != 0 {
		manager.mu.Unlock()
		t.Fatalf("expected no active alerts after initial exceedance")
	}

	if _, ok := manager.pendingAlerts["guest-123-cpu"]; !ok {
		manager.mu.Unlock()
		t.Fatalf("expected pending alert tracking to be started")
	}

	forcedStart := time.Now().Add(-3 * time.Second)
	manager.pendingAlerts["guest-123-cpu"] = forcedStart
	manager.mu.Unlock()

	// Second exceedance should trigger the alert using the pending start time.
	manager.checkMetric("guest-123", "test-vm", "node1", "qemu/123", "VM", "cpu", 90, threshold, nil)

	manager.mu.Lock()
	alert, exists := manager.activeAlerts["guest-123-cpu"]
	manager.mu.Unlock()

	if !exists {
		t.Fatalf("expected alert to be active after exceeding delay")
	}

	if !alert.StartTime.Equal(forcedStart) {
		t.Fatalf("expected alert start time %v, got %v", forcedStart, alert.StartTime)
	}
}
