package services

import (
	"testing"
	"time"

	"go.uber.org/zap"
)

func TestNewMonitoringAlertingService(t *testing.T) {
	config := MonitoringConfig{
		PrometheusURL: "",
		Logger:        zap.NewNop(),
	}

	service, err := NewMonitoringAlertingService(config)
	if err != nil {
		t.Fatalf("NewMonitoringAlertingService() error = %v", err)
	}

	if service == nil {
		t.Error("NewMonitoringAlertingService() returned nil")
	}
	if service.logger == nil {
		t.Error("NewMonitoringAlertingService() returned service with nil logger")
	}
	if service.rules == nil {
		t.Error("NewMonitoringAlertingService() returned service with nil rules")
	}
	if service.activeAlerts == nil {
		t.Error("NewMonitoringAlertingService() returned service with nil activeAlerts")
	}
}

func TestMonitoringAlertingService_AddAlertRule(t *testing.T) {
	config := MonitoringConfig{
		Logger: zap.NewNop(),
	}

	service, err := NewMonitoringAlertingService(config)
	if err != nil {
		t.Fatalf("NewMonitoringAlertingService() error = %v", err)
	}

	rule := AlertRule{
		Name:        "test_rule",
		Query:       "up",
		Threshold:   1.0,
		Severity:    SeverityWarning,
		Duration:    5 * time.Minute,
		Description: "Test rule",
		Enabled:     true,
	}

	service.AddAlertRule(rule)

	rules := service.GetAlertRules()
	if len(rules) != 1 {
		t.Errorf("AddAlertRule() rules count = %d, want 1", len(rules))
	}
	if rules[0].Name != "test_rule" {
		t.Errorf("AddAlertRule() rule name = %s, want test_rule", rules[0].Name)
	}
}

func TestMonitoringAlertingService_GetAlertRules(t *testing.T) {
	config := MonitoringConfig{
		Logger: zap.NewNop(),
	}

	service, err := NewMonitoringAlertingService(config)
	if err != nil {
		t.Fatalf("NewMonitoringAlertingService() error = %v", err)
	}

	// Add multiple rules
	service.AddAlertRule(AlertRule{Name: "rule1", Enabled: true})
	service.AddAlertRule(AlertRule{Name: "rule2", Enabled: true})

	rules := service.GetAlertRules()
	if len(rules) != 2 {
		t.Errorf("GetAlertRules() returned %d rules, want 2", len(rules))
	}
}

func TestMonitoringAlertingService_GetActiveAlerts(t *testing.T) {
	config := MonitoringConfig{
		Logger: zap.NewNop(),
	}

	service, err := NewMonitoringAlertingService(config)
	if err != nil {
		t.Fatalf("NewMonitoringAlertingService() error = %v", err)
	}

	alerts := service.GetActiveAlerts()
	if len(alerts) != 0 {
		t.Errorf("GetActiveAlerts() returned %d alerts, want 0", len(alerts))
	}
}

func TestMonitoringAlertingService_ResolveAlert(t *testing.T) {
	config := MonitoringConfig{
		Logger: zap.NewNop(),
	}

	service, err := NewMonitoringAlertingService(config)
	if err != nil {
		t.Fatalf("NewMonitoringAlertingService() error = %v", err)
	}

	// Try to resolve non-existent alert
	err = service.ResolveAlert("nonexistent")
	if err == nil {
		t.Error("ResolveAlert() should return error for non-existent alert")
	}
}

func TestMonitoringAlertingService_GetAlertByRuleName(t *testing.T) {
	config := MonitoringConfig{
		Logger: zap.NewNop(),
	}

	service, err := NewMonitoringAlertingService(config)
	if err != nil {
		t.Fatalf("NewMonitoringAlertingService() error = %v", err)
	}

	// Get non-existent alert
	alert, exists := service.GetAlertByRuleName("nonexistent")
	if exists {
		t.Error("GetAlertByRuleName() should return false for non-existent alert")
	}
	if alert != nil {
		t.Error("GetAlertByRuleName() should return nil for non-existent alert")
	}
}

func TestMonitoringAlertingService_SetNotificationFunc(t *testing.T) {
	config := MonitoringConfig{
		Logger: zap.NewNop(),
	}

	service, err := NewMonitoringAlertingService(config)
	if err != nil {
		t.Fatalf("NewMonitoringAlertingService() error = %v", err)
	}

	notificationCalled := false
	service.SetNotificationFunc(func(*MonitoringAlertNotification) error {
		notificationCalled = true
		return nil
	})

	// Verify function is set (can't test directly, but we can check it doesn't panic)
	if service == nil {
		t.Error("SetNotificationFunc() failed")
	}
	_ = notificationCalled
}

func TestGetDefaultAlertRules(t *testing.T) {
	rules := GetDefaultAlertRules()

	if len(rules) == 0 {
		t.Error("GetDefaultAlertRules() returned empty rules")
	}

	// Check that default rules have required fields
	for _, rule := range rules {
		if rule.Name == "" {
			t.Error("GetDefaultAlertRules() rule missing name")
		}
		if rule.Query == "" {
			t.Error("GetDefaultAlertRules() rule missing query")
		}
		if rule.Severity == "" {
			t.Error("GetDefaultAlertRules() rule missing severity")
		}
	}
}

func TestAlertSeverity_Constants(t *testing.T) {
	if SeverityCritical == "" {
		t.Error("SeverityCritical constant is empty")
	}
	if SeverityWarning == "" {
		t.Error("SeverityWarning constant is empty")
	}
	if SeverityInfo == "" {
		t.Error("SeverityInfo constant is empty")
	}
}

func TestAlertStatus_Constants(t *testing.T) {
	if AlertStatusFiring == "" {
		t.Error("AlertStatusFiring constant is empty")
	}
	if AlertStatusResolved == "" {
		t.Error("AlertStatusResolved constant is empty")
	}
	if AlertStatusPending == "" {
		t.Error("AlertStatusPending constant is empty")
	}
}

// Note: Full integration tests would require:
// 1. A running Prometheus instance
// 2. Actual metrics being exported
// 3. Verification of alert firing and resolution
// 4. Testing of notification functions
//
// Example integration test structure:
// func TestMonitoringAlertingService_CheckAlerts_Integration(t *testing.T) {
//     // Skip if Prometheus not available
//     prometheusURL := os.Getenv("PROMETHEUS_URL")
//     if prometheusURL == "" {
//         t.Skip("Prometheus not configured")
//     }
//
//     config := MonitoringConfig{
//         PrometheusURL: prometheusURL,
//         Logger:        zap.NewNop(),
//     }
//
//     service, err := NewMonitoringAlertingService(config)
//     if err != nil {
//         t.Fatalf("NewMonitoringAlertingService() error = %v", err)
//     }
//
//     // Add a test rule
//     rule := AlertRule{
//         Name:      "test_rule",
//         Query:     "up",
//         Threshold: 1.0,
//         Severity:  SeverityWarning,
//         Enabled:   true,
//     }
//     service.AddAlertRule(rule)
//
//     ctx := context.Background()
//     err = service.CheckAlerts(ctx)
//     if err != nil {
//         t.Fatalf("CheckAlerts() error = %v", err)
//     }
//
//     // Verify alerts were checked
//     alerts := service.GetActiveAlerts()
//     // Assert based on actual Prometheus metrics
// }
