package connector_outboundintent

import (
	"testing"
	"time"

	"github.com/pingcap-inc/nexuscrm-connectors/testing/connectorfixture"
)

func TestRepositoryNextWorkAtSchedulingBoundariesTiDB(t *testing.T) {
	db := connectorfixture.OpenTiDB(t)
	connectorfixture.CreateSystemTables(t, db, "_System_IntegrationOutboundCommand")
	now := time.Date(2026, 9, 2, 12, 0, 0, 123456000, time.UTC)
	future := now.Truncate(time.Second).Add(7 * time.Second)
	past := now.Truncate(time.Second).Add(-2 * time.Second)
	r := NewRepository(db)
	r.now = func() time.Time { return now }
	scope := outboundIntentTestScope()
	assertNext := func(t *testing.T, want time.Time) {
		t.Helper()
		got, found, err := r.NextWorkAt(t.Context(), scope)
		if err != nil || found != !want.IsZero() || !got.Equal(want) {
			t.Fatalf("NextWorkAt = (%v, %v, %v), want (%v, %v, nil)", got, found, err, want, !want.IsZero())
		}
	}
	assertNext(t, time.Time{})
	for _, tc := range []struct {
		name, state, token string
		next, lease        any
		want               time.Time
	}{
		{"pending uses clock microseconds", StatePending, "", nil, nil, now},
		{"retry deadline", StateRetry, "", future, nil, future},
		{"overdue retry", StateRetry, "", past, nil, past},
		{"claimed lease", StateClaimed, "owner", nil, future, future},
		{"expired claim", StateClaimed, "owner", nil, past, past},
		{"dispatch lease", StateDispatching, "owner", nil, future, future},
		{"missing lease uses clock", StateClaimed, "owner", nil, nil, now},
		{"writeback owned lease", StateWriteback, "owner", past, future, future},
		{"writeback expired lease", StateWriteback, "owner", future, past, future},
		{"writeback retry", StateWriteback, "", future, nil, future},
		{"writeback uses clock", StateWriteback, "", nil, nil, now},
		{"succeeded", StateSucceeded, "", past, past, time.Time{}},
		{"rejected", StateRejected, "", past, past, time.Time{}},
		{"uncertain requires reconciliation", StateUncertain, "", past, past, time.Time{}},
	} {
		t.Run(tc.name, func(t *testing.T) {
			if _, err := db.ExecContext(t.Context(), "DELETE FROM _System_IntegrationOutboundCommand"); err != nil {
				t.Fatal(err)
			}
			if _, _, err := r.Accept(t.Context(), scope, outboundIntentTestIntent(scope.CatalogRevision, "schedule", "record")); err != nil {
				t.Fatal(err)
			}
			if _, err := db.ExecContext(t.Context(), "UPDATE _System_IntegrationOutboundCommand SET State=?, ClaimToken=?, NextAttemptAt=?, LeaseExpiresAt=?", tc.state, tc.token, tc.next, tc.lease); err != nil {
				t.Fatal(err)
			}
			assertNext(t, tc.want)
		})
	}
	t.Run("minimum excludes blocked lane and other scope", func(t *testing.T) {
		if _, err := db.ExecContext(t.Context(), "DELETE FROM _System_IntegrationOutboundCommand"); err != nil {
			t.Fatal(err)
		}
		for _, input := range []struct {
			id, record string
			scope      Scope
			next       time.Time
		}{
			{"head", "blocked", scope, future.Add(time.Second)},
			{"successor", "blocked", scope, past},
			{"ready", "other", scope, future},
			{"outside", "outside", Scope{OrgID: "another-org", AppInstallationID: scope.AppInstallationID, AuthorizedWorkloadID: scope.AuthorizedWorkloadID, CatalogRevision: scope.CatalogRevision}, past},
		} {
			command, _, err := r.Accept(t.Context(), input.scope, outboundIntentTestIntent(input.scope.CatalogRevision, input.id, input.record))
			if err != nil {
				t.Fatal(err)
			}
			if _, err := db.ExecContext(t.Context(), "UPDATE _System_IntegrationOutboundCommand SET NextAttemptAt=? WHERE Id=?", input.next, command.CommandID); err != nil {
				t.Fatal(err)
			}
		}
		assertNext(t, future)
	})
}
