package delivery

import (
	"encoding/json"
	"log/slog"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/alertstore/pkg/alert"
	"github.com/tidbcloud/alertstore/pkg/jira"
)

func dispatcherFor(t *testing.T) *Dispatcher {
	t.Helper()
	return NewDispatcher(nil, nil, nil, jira.New(jira.Config{
		BaseURL:       "https://tidb.atlassian.net",
		User:          "bot@pingcap.com",
		Token:         "token",
		Project:       "O11Y",
		SummaryPrefix: "[PROD]",
	}, nil), slog.Default())
}

func alertFrom(t *testing.T, attrs alert.AlertAttrs) *alert.Alert {
	t.Helper()
	encoded, err := json.Marshal(attrs)
	require.NoError(t, err)
	return &alert.Alert{ID: "ALT-2607-42", State: alert.StateAcked, Attrs: encoded}
}

// Until a rule is handed over, anything reaching a person or an external system
// is jiralert's and jiraport's job, so doing it here would be the second time.
func TestShadowAlertsAreNotOwned(t *testing.T) {
	t.Parallel()

	d := dispatcherFor(t)

	owned := alertFrom(t, alert.AlertAttrs{Alertname: "TiKVDiskAlmostFull", Owned: true})
	require.True(t, d.owned(owned))
	require.True(t, d.jiraOwns(owned))

	shadow := alertFrom(t, alert.AlertAttrs{Alertname: "TiKVDiskAlmostFull"})
	require.False(t, d.owned(shadow))
	require.False(t, d.jiraOwns(shadow))
	require.False(t, d.shouldSyncTransition(shadow, "web"))
}

// The mirror has its own precondition, so it can be switched off independently.
func TestJiraMirrorCanBeOffForAnOwnedAlert(t *testing.T) {
	t.Parallel()

	d := NewDispatcher(nil, nil, nil, jira.New(jira.Config{}, nil), slog.Default())
	owned := alertFrom(t, alert.AlertAttrs{Owned: true})

	require.True(t, d.owned(owned))
	require.False(t, d.jiraOwns(owned))
	require.False(t, d.shouldSyncTransition(owned, "web"))
}

// alertstore walks a Jira close through open -> acked -> resolved; echoing the
// ack would drag the issue back to "In Progress" behind whoever closed it.
func TestTransitionsFromJiraAreNotEchoedBack(t *testing.T) {
	t.Parallel()

	d := dispatcherFor(t)
	a := alertFrom(t, alert.AlertAttrs{Owned: true})

	require.True(t, d.shouldSyncTransition(a, "web"))
	require.True(t, d.shouldSyncTransition(a, "im"))
	require.False(t, d.shouldSyncTransition(a, alert.SourceIssueTracker))
}

// The card is posted before the issue exists, so the link arrives with a later
// refresh and must not render as a dangling label before then.
func TestCardShowsTheJiraLinkOnlyOnceTheIssueExists(t *testing.T) {
	t.Parallel()

	attrs := &alert.AlertAttrs{Alertname: "TiKVDiskAlmostFull", Classification: alert.ClassPage}

	before := buildAlertBody(attrs, &alert.Alert{ID: "ALT-2607-42"}, "", "", "", "", nil)
	require.NotContains(t, before, "in Jira")

	mirrored := &alert.Alert{ID: "ALT-2607-42", ExternalIssueKey: "O11Y-42"}
	after := buildAlertBody(attrs, mirrored, "", "https://tidb.atlassian.net/browse/O11Y-42", "", "", nil)
	require.Contains(t, after, "O11Y-42 in Jira")
	require.Contains(t, after, "https://tidb.atlassian.net/browse/O11Y-42")
}

func TestJiraCommentIsTimestampedInBothOffices(t *testing.T) {
	t.Parallel()

	comment := timestamped("Alertmanager instance recovered: pod=tikv-0.")
	require.Contains(t, comment, "Alertmanager instance recovered: pod=tikv-0.")
	require.Regexp(t, `^\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [+-]\d{2} \| \d{4}-\d{2}-\d{2} `, comment)
}
