package notification

import (
	"fmt"
	"html"
	"strings"

	"github.com/prometheus/alertmanager/template"
)

const (
	// alert labels
	AlertLabelClusterID     = "cluster_id"
	AlertLabelTiDBClusterID = "tidb_cluster_id"
	AlertLabelProjectID     = "project_id"
	AlertLabelTenant        = "tenant"
	AlertLabelO11yTenantID  = "o11y_tenant_id"
	AlertLabelO11yBizType   = "o11y_biz_type"
	AlertLabelSeverity      = "severity"

	// alert annotations
	AlertAnnotationSubject = "description"
	AlertAnnotationContent = "message"

	// alert message placeholders
	PlaceholderClusterName = "TiDBClusterName"
	PlaceholderProjectName = "TiDBProjectName"
	PlaceholderDomainName  = "TiDBCloudDomainName"

	// webhook variables
	WebhookVariableAlertName    = "$ALERT_NAME"
	WebhookVariableMessage      = "$MESSAGE"
	WebhookVariableSeverity     = "$SEVERITY"
	WebhookVariableStartsAt     = "$STARTS_AT"
	WebhookVariableStartsAtISO  = "$ISO_STARTS_AT"
	WebhookVariableStartsAtTs   = "$STARTS_AT_TS"
	WebhookVariableEndsAt       = "$ENDS_AT"
	WebhookVariableEndsAtISO    = "$ISO_ENDS_AT"
	WebhookVariableStatus       = "$STATUS"
	WebhookVariablesClusterName = "$CLUSTER_NAME"
	WebhookVariablesProjectName = "$PROJECT_NAME"

	alertTimeFormatISO   = "2006-01-02T15:04:05Z07:00"
	alertTimeFormatFull  = "2006-01-02 15:04:05 -07:00"
	alertTimeFormatShort = "01-02 15:04"

	// used for account send email api
	NotificationSceneUserAlert = "useralert"

	// alert receiver
	AlertReceiverPrefix          = "default/observability-alertmanager-config/"
	AlertReceiverCustomer        = "customer"
	AlertReceiverPingCAPWarning  = "pingcap-warning"
	AlertReceiverPingCAPMajor    = "pingcap-major"
	AlertReceiverPingCAPCritical = "pingcap-critical"
)

type AlertMeta struct {
	TenantId    uint64
	ProjectId   uint64
	ProjectName string
	ClusterId   uint64
	ClusterName string
	// GroupKey identifies the Alertmanager group this alert arrived in. It is
	// forwarded to customers so they can deduplicate firing/resolved pairs and
	// our own retries.
	GroupKey string
}

func genTiDBCloudDomain(alert template.Alert) string {
	o11yBizType := alert.Labels[AlertLabelO11yBizType]
	domain := "tidbcloud.com"

	switch {
	case strings.HasPrefix(o11yBizType, "dev"):
		return fmt.Sprintf("dev.%s", domain)
	case strings.HasPrefix(o11yBizType, "staging"):
		return fmt.Sprintf("staging.%s", domain)
	}
	return domain
}

func replaceEmailMessage(
	message string,
	alert template.Alert,
	projectName, clusterName string,
) string {
	message = strings.ReplaceAll(message, PlaceholderClusterName,
		html.EscapeString(clusterName))
	if len(projectName) > 0 {
		message = strings.ReplaceAll(message, PlaceholderProjectName,
			html.EscapeString(projectName))
	}
	message = strings.ReplaceAll(message, PlaceholderDomainName,
		html.EscapeString(genTiDBCloudDomain(alert)))
	return message
}

func replaceWebhookPayload(
	payload string,
	alert template.Alert,
	projectName, clusterName string,
) string {
	payload = strings.ReplaceAll(payload, WebhookVariableAlertName,
		escapeString(alert.Annotations[AlertAnnotationSubject]))
	payload = strings.ReplaceAll(payload, WebhookVariableMessage,
		escapeString(replaceEmailMessage(
			alert.Annotations[AlertAnnotationContent],
			alert,
			projectName,
			clusterName,
		)))
	severity := alert.Labels[AlertLabelSeverity]
	if strings.ToLower(severity) == "major" {
		severity = "warning"
	}
	payload = strings.ReplaceAll(payload, WebhookVariableSeverity,
		escapeString(severity))
	payload = strings.ReplaceAll(payload, WebhookVariableStartsAt,
		escapeString(alert.StartsAt.Format(alertTimeFormatFull)))
	payload = strings.ReplaceAll(payload, WebhookVariableStartsAtISO,
		escapeString(alert.StartsAt.Format(alertTimeFormatISO)))
	payload = strings.ReplaceAll(payload, WebhookVariableStartsAtTs,
		escapeString(fmt.Sprintf("%d", alert.StartsAt.Unix())))
	payload = strings.ReplaceAll(payload, WebhookVariableEndsAtISO,
		escapeString(alert.EndsAt.Format(alertTimeFormatISO)))
	payload = strings.ReplaceAll(payload, WebhookVariableEndsAt,
		escapeString(alert.EndsAt.Format(alertTimeFormatFull)))
	payload = strings.ReplaceAll(payload, WebhookVariableStatus,
		escapeString(alert.Status))
	payload = strings.ReplaceAll(payload, WebhookVariablesClusterName,
		escapeString(clusterName))
	payload = strings.ReplaceAll(payload, WebhookVariablesProjectName,
		escapeString(projectName))
	return payload
}

func escapeString(s string) string {
	// escapeString is used to inject alert content into JSON templates.
	// It must ensure the resulting JSON remains valid.
	// We escape backslash first to avoid double-escaping sequences.
	s = strings.ReplaceAll(s, "\\", "\\\\")
	s = strings.ReplaceAll(s, "\"", "\\\"")
	s = strings.ReplaceAll(s, "\n", "\\n")
	s = strings.ReplaceAll(s, "\r", "\\r")
	s = strings.ReplaceAll(s, "\t", "\\t")
	return s
}

// example:
// input: url prefix messages <a href="https://testurl.com">Display Links</a> blabla
// output: url prefix messages <https://testurl.com|Display Links> blabla
func replaceHtmlLink(payload string) string {
	payload = strings.ReplaceAll(payload, "<a href=\\\"", "<")
	payload = strings.ReplaceAll(payload, "<a href=\"", "<")
	payload = strings.ReplaceAll(payload, "\\\">", "|")
	payload = strings.ReplaceAll(payload, "\">", "|")
	payload = strings.ReplaceAll(payload, "</a>", ">")
	return payload
}

func replaceEmailLineBreak(payload string) string {
	payload = strings.ReplaceAll(payload, "\n", "<br>")
	return payload
}
