package notify

import (
	"bytes"
	"crypto/sha512"
	"fmt"
	"strings"
	"time"

	"github.com/go-kit/kit/log/level"

	"github.com/prometheus-community/jiralert/pkg/alertmanager"
)

func (r *Receiver) GetCustomGroupLabels(data *alertmanager.Data) []string {
	if r.conf.CustomGroupLabels == nil {
		return make([]string, 0)
	}
	de := r.conf.CustomGroupLabels.Default
	for _, extend := range r.conf.CustomGroupLabels.Extended {
		val, err := r.tmpl.Execute(extend.Extracted, data)
		if err != nil {
			level.Warn(r.logger).Log("msg", "fail when render the extracted value", "extracted", extend.Extracted)
			continue
		}
		for k, v := range extend.Conditions {
			if k == val {
				de = append(de, v...)
			}
		}
	}
	return de
}

// toGroupTicketLabel returns the group labels as a single string.
// This is used to reference each ticket groups.
// (old) default behavior: String is the form of an ALERT Prometheus metric name, with all spaces removed.
// new opt-in behavior: String is the form of JIRALERT{sha512hash(groupLabels)}
// hashing ensures that JIRA validation still accepts the output even
// if the combined length of all groupLabel key-value pairs would be
// longer than 255 chars
func toGroupTicketLabel(data *alertmanager.Data, hashJiraLabel bool, hashWithStartsAt bool) string {
	groupLabels := data.GroupLabels
	// for specific alert, no need to drop duplicate.
	if len(data.Alerts) > 0 && data.Alerts[0].Labels["alertname"] == "GCSafePointNotAdvancing" {
		hashWithStartsAt = true
	}
	// new opt in behavior
	if hashJiraLabel {
		hash := sha512.New()
		for _, p := range groupLabels.SortedPairs() {
			kvString := fmt.Sprintf("%s=%q,", p.Name, p.Value)
			_, _ = hash.Write([]byte(kvString)) // hash.Write can never return an error
		}
		if hashWithStartsAt {
			for _, a := range data.Alerts {
				tString := a.StartsAt.Format(time.RFC3339Nano)
				_, _ = hash.Write([]byte(tString))
			}
		}
		return fmt.Sprintf("JIRALERT{%x}", hash.Sum(nil))
	}

	// old default behavior
	buf := bytes.NewBufferString("ALERT{")
	for _, p := range groupLabels.SortedPairs() {
		buf.WriteString(p.Name)
		buf.WriteString(fmt.Sprintf("=%q,", p.Value))
	}
	buf.Truncate(buf.Len() - 1)
	buf.WriteString("}")
	return strings.Replace(buf.String(), " ", "", -1)
}

// toCustomGroupTicketLabel generate custom group label with selected labels
func toCustomGroupTicketLabel(data *alertmanager.Data, selectedLabels []string) string {
	groupLabels := data.GroupLabels

	hash := sha512.New()
	for _, l := range selectedLabels {
		v, ok := groupLabels[l]
		if ok {
			kvString := fmt.Sprintf("%s=%q,", l, v)
			_, _ = hash.Write([]byte(kvString))
		}
	}
	return fmt.Sprintf("CUSTOMGROUP{%x}", hash.Sum(nil))
}
