package alerting

import (
	"fmt"
	"sync"
	"time"
)

// AlertLevel represents alert severity
type AlertLevel string

const (
	AlertWarning  AlertLevel = "warning"
	AlertError    AlertLevel = "error"
	AlertCritical AlertLevel = "critical"
)

// Alert represents an alert notification
type Alert struct {
	ID        string
	Level     AlertLevel
	Title     string
	Message   string
	Timestamp time.Time
	Resolved  bool
	Source    string
}

// AlertRule represents a rule that triggers alerts
type AlertRule struct {
	ID        string
	Name      string
	Threshold float64
	Metric    string
	Level     AlertLevel
}

// AlertManager manages alert rules and notifications
type AlertManager struct {
	mu       sync.RWMutex
	rules    map[string]*AlertRule
	alerts   map[string]*Alert
	history  []*Alert
}

// NewAlertManager creates a new alert manager
func NewAlertManager() *AlertManager {
	return &AlertManager{
		rules:   make(map[string]*AlertRule),
		alerts:  make(map[string]*Alert),
		history: make([]*Alert, 0),
	}
}

// AddRule adds an alert rule
func (am *AlertManager) AddRule(rule *AlertRule) error {
	if rule.ID == "" || rule.Name == "" {
		return fmt.Errorf("rule ID and name required")
	}

	am.mu.Lock()
	defer am.mu.Unlock()

	am.rules[rule.ID] = rule
	return nil
}

// RemoveRule removes an alert rule
func (am *AlertManager) RemoveRule(ruleID string) error {
	am.mu.Lock()
	defer am.mu.Unlock()

	if _, exists := am.rules[ruleID]; !exists {
		return fmt.Errorf("rule not found: %s", ruleID)
	}

	delete(am.rules, ruleID)
	return nil
}

// TriggerAlert triggers a new alert
func (am *AlertManager) TriggerAlert(title, message string, level AlertLevel) (*Alert, error) {
	if title == "" {
		return nil, fmt.Errorf("alert title required")
	}

	am.mu.Lock()
	defer am.mu.Unlock()

	alert := &Alert{
		ID:        fmt.Sprintf("alert-%d", len(am.alerts)),
		Level:     level,
		Title:     title,
		Message:   message,
		Timestamp: time.Now(),
		Resolved:  false,
	}

	am.alerts[alert.ID] = alert
	am.history = append(am.history, alert)

	return alert, nil
}

// ResolveAlert marks an alert as resolved
func (am *AlertManager) ResolveAlert(alertID string) error {
	am.mu.Lock()
	defer am.mu.Unlock()

	alert, exists := am.alerts[alertID]
	if !exists {
		return fmt.Errorf("alert not found: %s", alertID)
	}

	alert.Resolved = true
	return nil
}

// GetActiveAlerts returns all unresolved alerts
func (am *AlertManager) GetActiveAlerts() []*Alert {
	am.mu.RLock()
	defer am.mu.RUnlock()

	result := make([]*Alert, 0)
	for _, alert := range am.alerts {
		if !alert.Resolved {
			result = append(result, alert)
		}
	}

	return result
}

// GetAlertsByLevel returns alerts by severity level
func (am *AlertManager) GetAlertsByLevel(level AlertLevel) []*Alert {
	am.mu.RLock()
	defer am.mu.RUnlock()

	result := make([]*Alert, 0)
	for _, alert := range am.alerts {
		if alert.Level == level {
			result = append(result, alert)
		}
	}

	return result
}

// GetHistory returns alert history
func (am *AlertManager) GetHistory() []*Alert {
	am.mu.RLock()
	defer am.mu.RUnlock()

	result := make([]*Alert, len(am.history))
	copy(result, am.history)

	return result
}

// GetRules returns all alert rules
func (am *AlertManager) GetRules() map[string]*AlertRule {
	am.mu.RLock()
	defer am.mu.RUnlock()

	result := make(map[string]*AlertRule)
	for id, rule := range am.rules {
		result[id] = rule
	}

	return result
}

// GetAlertCount returns total active alert count
func (am *AlertManager) GetAlertCount() int {
	am.mu.RLock()
	defer am.mu.RUnlock()

	return len(am.alerts)
}

// Clear clears all alerts
func (am *AlertManager) Clear() {
	am.mu.Lock()
	defer am.mu.Unlock()

	am.alerts = make(map[string]*Alert)
}

// EvaluateRule checks if a metric triggers an alert rule
func (am *AlertManager) EvaluateRule(ruleID string, metricValue float64) (*Alert, error) {
	am.mu.Lock()
	defer am.mu.Unlock()

	rule, exists := am.rules[ruleID]
	if !exists {
		return nil, fmt.Errorf("rule not found: %s", ruleID)
	}

	if metricValue >= rule.Threshold {
		alert := &Alert{
			ID:        fmt.Sprintf("alert-%d", len(am.alerts)),
			Level:     rule.Level,
			Title:     rule.Name,
			Message:   fmt.Sprintf("Threshold %.2f exceeded: %.2f", rule.Threshold, metricValue),
			Timestamp: time.Now(),
			Resolved:  false,
			Source:    ruleID,
		}

		am.alerts[alert.ID] = alert
		am.history = append(am.history, alert)

		return alert, nil
	}

	return nil, nil
}
