package platform

import (
	"context"
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"strings"
)

type alertStore interface {
	AlertSummary(context.Context, AlertQuery) (AlertSummary, error)
	AlertEvents(context.Context, AlertQuery) (Page[AlertEvent], error)
	AlertEvent(context.Context, string) (AlertEvent, error)
	AlertRules(context.Context) ([]AlertRule, error)
	SaveAlertRule(context.Context, AlertRuleInput) (AlertRule, error)
	SetAlertRuleEnabled(context.Context, string, AlertRuleEnabledUpdate) (AlertRule, error)
	ActOnAlert(context.Context, string, AlertActionRequest) (AlertEvent, error)
	AlertNotifications(context.Context, AlertNotificationQuery) (Page[AlertNotification], error)
	MarkAlertNotificationsRead(context.Context, AlertNotificationReadRequest) (int, error)
}

type alertEvaluatorStore interface {
	EvaluateAlerts(context.Context) (AlertEvaluationResult, error)
}

func (s *Service) alertStore() (alertStore, error) {
	store, ok := s.store.(alertStore)
	if !ok {
		return nil, fmt.Errorf("store does not provide durable alert center")
	}
	return store, nil
}

func (s *Service) AlertSummary(ctx context.Context, query AlertQuery) (AlertSummary, error) {
	store, err := s.alertStore()
	if err != nil {
		return AlertSummary{}, err
	}
	return store.AlertSummary(ctx, normalizeAlertQuery(query))
}

func (s *Service) AlertEvents(ctx context.Context, query AlertQuery) (Page[AlertEvent], error) {
	if principal, ok := PrincipalFromContext(ctx); ok && principal.UserType == "customer" {
		if strings.TrimSpace(query.Keyword) == "" {
			return Page[AlertEvent]{}, clientError{Code: "VEHICLE_PERMISSION_DENIED", Message: "客户账号仅可查询已授权车辆的告警"}
		}
		vin, err := s.resolveVehicleVIN(ctx, query.Keyword, query.Protocol)
		if err != nil {
			return Page[AlertEvent]{}, err
		}
		if err := authorizeVehicleVIN(ctx, vin); err != nil {
			return Page[AlertEvent]{}, err
		}
		query.Keyword = vin
	}
	store, err := s.alertStore()
	if err != nil {
		return Page[AlertEvent]{}, err
	}
	return store.AlertEvents(ctx, normalizeAlertQuery(query))
}

func (s *Service) AlertEvent(ctx context.Context, id string) (AlertEvent, error) {
	if strings.TrimSpace(id) == "" {
		return AlertEvent{}, clientError{Code: "ALERT_EVENT_ID_REQUIRED", Message: "告警事件 ID 不能为空"}
	}
	store, err := s.alertStore()
	if err != nil {
		return AlertEvent{}, err
	}
	return store.AlertEvent(ctx, strings.TrimSpace(id))
}

func (s *Service) AlertRules(ctx context.Context) ([]AlertRule, error) {
	store, err := s.alertStore()
	if err != nil {
		return nil, err
	}
	return store.AlertRules(ctx)
}

func (s *Service) SaveAlertRule(ctx context.Context, input AlertRuleInput) (AlertRule, error) {
	definitions, err := s.metricDefinitions(ctx)
	if err != nil {
		return AlertRule{}, err
	}
	if err := validateAlertRule(input, definitions...); err != nil {
		return AlertRule{}, err
	}
	input.ID = strings.TrimSpace(input.ID)
	if input.ID == "" {
		id, err := newAlertID("rule")
		if err != nil {
			return AlertRule{}, err
		}
		input.ID = id
	}
	input.Actor = firstNonEmpty(strings.TrimSpace(input.Actor), "platform-admin")
	input.ScopeProtocols = cleanUniqueStrings(input.ScopeProtocols)
	input.ScopeVINs = cleanUniqueStrings(input.ScopeVINs)
	input.ScopeOEMs = cleanUniqueStrings(input.ScopeOEMs)
	input.ScopeModels = cleanUniqueStrings(input.ScopeModels)
	input.ScopeCompanies = cleanUniqueStrings(input.ScopeCompanies)
	if err := validateAlertRuleScopes(input); err != nil {
		return AlertRule{}, err
	}
	input.NotificationChannels = normalizeAlertChannels(input.NotificationChannels)
	if strings.EqualFold(input.Operator, "changed") {
		input.DurationSec = 0
	}
	if strings.EqualFold(input.ValueType, "boolean") && input.BooleanThreshold != nil {
		if *input.BooleanThreshold {
			input.Threshold = 1
		} else {
			input.Threshold = 0
		}
	}
	store, err := s.alertStore()
	if err != nil {
		return AlertRule{}, err
	}
	return store.SaveAlertRule(ctx, input)
}

func validateAlertRuleScopes(input AlertRuleInput) error {
	for _, scope := range []struct {
		name   string
		values []string
	}{
		{"协议", input.ScopeProtocols}, {"VIN", input.ScopeVINs}, {"厂家", input.ScopeOEMs},
		{"车型", input.ScopeModels}, {"企业", input.ScopeCompanies},
	} {
		if len(scope.values) > 500 {
			return clientError{Code: "ALERT_RULE_SCOPE_TOO_LARGE", Message: scope.name + "范围最多允许 500 项"}
		}
		for _, value := range scope.values {
			if len([]rune(value)) > 128 {
				return clientError{Code: "ALERT_RULE_SCOPE_VALUE_INVALID", Message: scope.name + "范围值不能超过 128 个字符"}
			}
		}
	}
	return nil
}

func (s *Service) SetAlertRuleEnabled(ctx context.Context, id string, update AlertRuleEnabledUpdate) (AlertRule, error) {
	if strings.TrimSpace(id) == "" || update.Version <= 0 {
		return AlertRule{}, clientError{Code: "ALERT_RULE_VERSION_REQUIRED", Message: "规则 ID 和版本不能为空"}
	}
	update.Actor = firstNonEmpty(strings.TrimSpace(update.Actor), "platform-admin")
	store, err := s.alertStore()
	if err != nil {
		return AlertRule{}, err
	}
	return store.SetAlertRuleEnabled(ctx, strings.TrimSpace(id), update)
}

func (s *Service) ActOnAlert(ctx context.Context, id string, request AlertActionRequest) (AlertEvent, error) {
	if strings.TrimSpace(id) == "" || request.Version <= 0 {
		return AlertEvent{}, clientError{Code: "ALERT_EVENT_VERSION_REQUIRED", Message: "事件 ID 和版本不能为空"}
	}
	request.Action = strings.ToLower(strings.TrimSpace(request.Action))
	if request.Action != "acknowledge" && request.Action != "close" && request.Action != "ignore" {
		return AlertEvent{}, clientError{Code: "ALERT_ACTION_INVALID", Message: "仅支持确认、关闭或忽略告警"}
	}
	if len([]rune(request.Note)) > 200 {
		return AlertEvent{}, clientError{Code: "ALERT_NOTE_TOO_LONG", Message: "处置备注不能超过 200 字"}
	}
	request.Actor = firstNonEmpty(strings.TrimSpace(request.Actor), "platform-admin")
	store, err := s.alertStore()
	if err != nil {
		return AlertEvent{}, err
	}
	return store.ActOnAlert(ctx, strings.TrimSpace(id), request)
}

func (s *Service) AlertNotifications(ctx context.Context, query AlertNotificationQuery) (Page[AlertNotification], error) {
	if query.Limit <= 0 {
		query.Limit = 20
	}
	if query.Limit > 100 {
		query.Limit = 100
	}
	if query.Offset < 0 {
		query.Offset = 0
	}
	store, err := s.alertStore()
	if err != nil {
		return Page[AlertNotification]{}, err
	}
	return store.AlertNotifications(ctx, query)
}

func (s *Service) MarkAlertNotificationsRead(ctx context.Context, request AlertNotificationReadRequest) (int, error) {
	if len(request.IDs) == 0 || len(request.IDs) > 100 {
		return 0, clientError{Code: "ALERT_NOTIFICATION_IDS_INVALID", Message: "请选择 1 到 100 条通知"}
	}
	request.Actor = firstNonEmpty(strings.TrimSpace(request.Actor), "platform-admin")
	store, err := s.alertStore()
	if err != nil {
		return 0, err
	}
	return store.MarkAlertNotificationsRead(ctx, request)
}

func (s *Service) EvaluateAlerts(ctx context.Context) (AlertEvaluationResult, error) {
	store, ok := s.store.(alertEvaluatorStore)
	if !ok {
		return AlertEvaluationResult{}, fmt.Errorf("store does not provide alert evaluation")
	}
	return store.EvaluateAlerts(ctx)
}

func normalizeAlertQuery(query AlertQuery) AlertQuery {
	query.Keyword = strings.TrimSpace(query.Keyword)
	query.Severity = strings.ToLower(strings.TrimSpace(query.Severity))
	query.Status = strings.ToLower(strings.TrimSpace(query.Status))
	query.RuleID = strings.TrimSpace(query.RuleID)
	query.Protocol = strings.TrimSpace(query.Protocol)
	if query.Limit <= 0 {
		query.Limit = 20
	}
	if query.Limit > 200 {
		query.Limit = 200
	}
	if query.Offset < 0 {
		query.Offset = 0
	}
	return query
}

func validateAlertRule(input AlertRuleInput, catalog ...MetricDefinition) error {
	if strings.TrimSpace(input.Name) == "" || len([]rune(input.Name)) > 80 {
		return clientError{Code: "ALERT_RULE_NAME_INVALID", Message: "规则名称不能为空且不能超过 80 字"}
	}
	severity := strings.ToLower(strings.TrimSpace(input.Severity))
	if severity != "critical" && severity != "major" && severity != "minor" {
		return clientError{Code: "ALERT_RULE_SEVERITY_INVALID", Message: "告警级别仅支持 critical、major、minor"}
	}
	valueType := strings.ToLower(strings.TrimSpace(input.ValueType))
	if valueType != "numeric" && valueType != "boolean" {
		return clientError{Code: "ALERT_RULE_VALUE_TYPE_INVALID", Message: "规则值类型仅支持 numeric 或 boolean"}
	}
	if strings.TrimSpace(input.Metric) == "" {
		return clientError{Code: "ALERT_RULE_METRIC_REQUIRED", Message: "规则指标不能为空"}
	}
	var metric *MetricDefinition
	definitions := catalog
	if len(definitions) == 0 {
		definitions = metricDefinitions()
	}
	for index := range definitions {
		candidate := definitions[index]
		if candidate.Key == strings.TrimSpace(input.Metric) {
			metric = &candidate
			break
		}
	}
	if metric == nil || !metric.Alertable {
		return clientError{Code: "ALERT_RULE_METRIC_INVALID", Message: "规则指标不在可告警指标目录中"}
	}
	if _, supported := alertMetricValue(input.Metric, alertEvaluationEvidence{}); !supported {
		return clientError{Code: "ALERT_RULE_METRIC_UNSUPPORTED", Message: "规则指标尚未接入告警评估器"}
	}
	if metric.ValueType != valueType {
		return clientError{Code: "ALERT_RULE_METRIC_TYPE_MISMATCH", Message: "规则值类型与指标目录不一致"}
	}
	operator := strings.ToLower(strings.TrimSpace(input.Operator))
	allowed := map[string]bool{"gt": true, "gte": true, "lt": true, "lte": true, "eq": true, "neq": true, "between": true, "outside": true, "changed": true}
	if !allowed[operator] {
		return clientError{Code: "ALERT_RULE_OPERATOR_INVALID", Message: "规则比较符无效"}
	}
	if (operator == "between" || operator == "outside") && (valueType != "numeric" || input.ThresholdHigh <= input.Threshold) {
		return clientError{Code: "ALERT_RULE_RANGE_INVALID", Message: "区间规则必须是数值型且上限大于下限"}
	}
	if operator == "changed" && valueType != "boolean" {
		return clientError{Code: "ALERT_RULE_CHANGE_INVALID", Message: "状态变化规则必须使用布尔值类型"}
	}
	if valueType == "boolean" && operator != "changed" && input.BooleanThreshold == nil {
		return clientError{Code: "ALERT_RULE_BOOLEAN_REQUIRED", Message: "布尔规则必须配置目标值"}
	}
	if input.DurationSec < 0 || input.DurationSec > 86400 || input.RepeatIntervalSec < 0 || input.RepeatIntervalSec > 604800 {
		return clientError{Code: "ALERT_RULE_INTERVAL_INVALID", Message: "持续时间或重复间隔超出允许范围"}
	}
	if input.Version < 0 {
		return clientError{Code: "ALERT_RULE_VERSION_INVALID", Message: "规则版本无效"}
	}
	return nil
}

func normalizeAlertChannels(values []string) []string {
	allowed := map[string]bool{"in_app": true, "sms": true, "email": true, "wecom": true}
	out := make([]string, 0, len(values)+1)
	seen := map[string]bool{}
	for _, value := range values {
		value = strings.ToLower(strings.TrimSpace(value))
		if allowed[value] && !seen[value] {
			seen[value] = true
			out = append(out, value)
		}
	}
	if !seen["in_app"] {
		out = append([]string{"in_app"}, out...)
	}
	return out
}

func cleanUniqueStrings(values []string) []string {
	out := make([]string, 0, len(values))
	seen := map[string]bool{}
	for _, value := range values {
		value = strings.TrimSpace(value)
		if value != "" && !seen[value] {
			seen[value] = true
			out = append(out, value)
		}
	}
	return out
}

func newAlertID(prefix string) (string, error) {
	buf := make([]byte, 10)
	if _, err := rand.Read(buf); err != nil {
		return "", err
	}
	return prefix + "-" + hex.EncodeToString(buf), nil
}
