package action

import (
	"testing"

	"github.com/andygrunwald/go-jira"
	"github.com/trivago/tgo/tcontainer"

	"github.com/tidbcloud/jiraport/pkg/entity"
)

// issueWithAlertData builds an issue whose customfield_10160 holds the raw alert
// JSON jiralert stores there. A nil rawAlert means the field is absent.
func issueWithAlertData(rawAlert interface{}) *entity.Issue {
	unknowns := tcontainer.NewMarshalMap()
	if rawAlert != nil {
		unknowns["customfield_10160"] = rawAlert
	}
	return &entity.Issue{
		RawIssue: entity.RawIssue{Fields: &jira.IssueFields{Unknowns: unknowns}},
	}
}

func TestHandedOverToAlertstore(t *testing.T) {
	tests := []struct {
		name     string
		rawAlert interface{}
		want     bool
	}{
		{
			name:     "no label",
			rawAlert: `{"labels":{"alertname":"TiKVDiskAlmostFull"}}`,
			want:     false,
		},
		{
			// The value is the response tier, so any tier hands the rule over.
			name:     "page tier",
			rawAlert: `{"labels":{"alertname":"TiKVDiskAlmostFull","response_class":"page"}}`,
			want:     true,
		},
		{
			name:     "ticket tier",
			rawAlert: `{"labels":{"response_class":"ticket"}}`,
			want:     true,
		},
		{
			// Presence is the signal. Kept in step with jiralert's canary_test.go.
			name:     "empty value is still a handover",
			rawAlert: `{"labels":{"response_class":""}}`,
			want:     true,
		},
		{
			// A rollback must not require deleting the label.
			name:     "falsy value rolls the rule back",
			rawAlert: `{"labels":{"response_class":"false"}}`,
			want:     false,
		},
		{
			name:     "off rolls the rule back",
			rawAlert: `{"labels":{"response_class":" OFF "}}`,
			want:     false,
		},
		{
			// Support tickets and anything else not filed for an alert.
			name:     "not an alert issue",
			rawAlert: nil,
			want:     false,
		},
		{
			name:     "unparseable alert data",
			rawAlert: `not json`,
			want:     false,
		},
		{
			name:     "non-string alert data",
			rawAlert: 1,
			want:     false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := handedOverToAlertstore(issueWithAlertData(tt.rawAlert)); got != tt.want {
				t.Fatalf("handedOverToAlertstore() = %v, want %v", got, tt.want)
			}
		})
	}

	if handedOverToAlertstore(nil) {
		t.Fatal("handedOverToAlertstore(nil) = true, want false")
	}
}

func TestSuppressedByHandover(t *testing.T) {
	handedOver := `{"labels":{"response_class":"page"}}`

	tests := []struct {
		name     string
		cmd      []string
		rawAlert interface{}
		want     bool
	}{
		{name: "notify", cmd: []string{"notify", "phone", "assignee", "oncall"}, rawAlert: handedOver, want: true},
		{name: "assign", cmd: []string{"assign", "oncall"}, rawAlert: handedOver, want: true},
		{name: "escalate", cmd: []string{"escalate"}, rawAlert: handedOver, want: true},
		{name: "L2 assign", cmd: []string{"custom", "customfield_10053"}, rawAlert: handedOver, want: true},
		// alertstore does not enrich the issue, so these keep running.
		{name: "backfill", cmd: []string{"backfill"}, rawAlert: handedOver, want: false},
		{name: "report", cmd: []string{"report"}, rawAlert: handedOver, want: false},
		{name: "comment", cmd: []string{"comment", "hello"}, rawAlert: handedOver, want: false},
		{name: "timeout", cmd: []string{"timeout", "480"}, rawAlert: handedOver, want: false},
		// The same commands on an alert jiraport still answers.
		{name: "notify, not handed over", cmd: []string{"notify", "phone", "assignee", "oncall"}, rawAlert: `{"labels":{}}`, want: false},
		{name: "assign, not an alert issue", cmd: []string{"assign", "oncall"}, rawAlert: nil, want: false},
		{name: "empty command", cmd: nil, rawAlert: handedOver, want: false},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := suppressedByHandover(issueWithAlertData(tt.rawAlert), tt.cmd)
			if got != tt.want {
				t.Fatalf("suppressedByHandover(%v) = %v, want %v", tt.cmd, got, tt.want)
			}
		})
	}
}
