package roles

import (
	"context"
	"math"
	"sync/atomic"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
	rolesstore "github.com/tidbcloud/AgentTeam/internal/store/resource/roles"
	"gorm.io/gorm"
)

type nativeRoleHistoryGate struct{ RolePackageContentStore }

func (nativeRoleHistoryGate) NativeRolePackageRead(context.Context, string, string) (bool, error) {
	return true, nil
}

func TestListRoleVersionsUsesExactBoundedHistory(t *testing.T) {
	ctx := context.Background()
	svc := newRoleServiceForTest(t, Options{})
	svc.contentStore = nativeRoleHistoryGate{}
	now := time.Date(2026, 8, 21, 3, 0, 0, 0, time.UTC)
	_, err := svc.store.CreateRole(ctx, rolesstore.Role{
		ID: "role_1", WorkspaceID: "wsp_1", Slug: "reviewer", Name: "Reviewer", Description: "review",
		TagsJSON: "[]", Definition: "active", RuntimeHintsJSON: "{}", AttachmentsJSON: "[]",
		Visibility: RoleVisibilityPrivate, ActiveVersionID: "rlv_c", IsActive: true,
		CreatedBy: "usr_1", UpdatedBy: "usr_1", CreatedAt: now, UpdatedAt: now,
	})
	require.NoError(t, err)
	for _, version := range []rolesstore.RoleVersion{
		{ID: "rlv_legacy", RoleID: "role_1", WorkspaceID: "wsp_1", Version: 1, Status: "published", Definition: "legacy", RuntimeHintsJSON: "{}", ProvenanceJSON: "{}", NonPortableSummaryJSON: "[]", CreatedBy: "usr_1", CreatedAt: now.Add(-time.Minute)},
		{ID: "rlv_a", RoleID: "role_1", WorkspaceID: "wsp_1", Version: 2, Status: "published", Definition: "a", RuntimeHintsJSON: "{}", ProvenanceJSON: "{}", NonPortableSummaryJSON: "[]", ContentID: "ctn_1", ContentVersionID: "ctv_a", CreatedBy: "usr_1", CreatedAt: now},
		{ID: "rlv_b", RoleID: "role_1", WorkspaceID: "wsp_1", Version: 3, Status: "published", Definition: "b", RuntimeHintsJSON: "{}", ProvenanceJSON: "{}", NonPortableSummaryJSON: "[]", ContentID: "ctn_1", ContentVersionID: "ctv_b", CreatedBy: "usr_1", CreatedAt: now},
		{ID: "rlv_c", RoleID: "role_1", WorkspaceID: "wsp_1", Version: 4, Status: "published", Definition: "c", RuntimeHintsJSON: "{}", ProvenanceJSON: "{}", NonPortableSummaryJSON: "[]", ContentID: "ctn_1", ContentVersionID: "ctv_c", CreatedBy: "usr_1", CreatedAt: now.Add(time.Minute)},
		{ID: "rlv_other_lineage", RoleID: "role_1", WorkspaceID: "wsp_1", Version: 5, Status: "published", Definition: "other", RuntimeHintsJSON: "{}", ProvenanceJSON: "{}", NonPortableSummaryJSON: "[]", ContentID: "ctn_other", ContentVersionID: "ctv_other", CreatedBy: "usr_1", CreatedAt: now.Add(time.Hour)},
	} {
		require.NoError(t, svc.store.DB().Create(&version).Error)
	}

	page, err := svc.ListRoleVersions(ctx, "wsp_1", "usr_1", "role_1", 1, 2)
	require.NoError(t, err)
	require.Len(t, page.Items, 2)
	require.True(t, page.HasMore)
	require.Equal(t, []string{"rlv_c", "rlv_b"}, []string{page.Items[0].ID, page.Items[1].ID})
	require.True(t, page.Items[0].Active)
	require.False(t, page.Items[1].Active)
}

func TestListRoleVersionsRequiresNativeAuthorityBeforeHistoryQuery(t *testing.T) {
	ctx := context.Background()
	svc := newRoleServiceForTest(t, Options{})
	now := time.Date(2026, 8, 21, 3, 0, 0, 0, time.UTC)
	_, err := svc.store.CreateRole(ctx, rolesstore.Role{
		ID: "role_legacy", WorkspaceID: "wsp_1", Slug: "legacy", Name: "Legacy", Definition: "legacy",
		TagsJSON: "[]", RuntimeHintsJSON: "{}", AttachmentsJSON: "[]", Visibility: RoleVisibilityPrivate,
		ActiveVersionID: "rlv_legacy", IsActive: true, CreatedBy: "usr_1", UpdatedBy: "usr_1", CreatedAt: now, UpdatedAt: now,
	})
	require.NoError(t, err)
	require.NoError(t, svc.store.DB().Create(&rolesstore.RoleVersion{
		ID: "rlv_legacy", RoleID: "role_legacy", WorkspaceID: "wsp_1", Version: 1, Status: "published",
		Definition: "legacy", RuntimeHintsJSON: "{}", ProvenanceJSON: "{}", NonPortableSummaryJSON: "[]",
		ContentID: "ctn_stale", ContentVersionID: "ctv_stale", CreatedBy: "usr_1", CreatedAt: now,
	}).Error)

	var historyQueries atomic.Int64
	require.NoError(t, svc.store.DB().Callback().Query().Before("gorm:query").Register("test:role_history_authority_gate", func(tx *gorm.DB) {
		if tx.Statement != nil && tx.Statement.Schema != nil && tx.Statement.Schema.Table == (rolesstore.RoleVersion{}).TableName() {
			historyQueries.Add(1)
		}
	}))
	_, err = svc.ListRoleVersions(ctx, "wsp_1", "usr_1", "role_legacy", 1, 20)
	require.ErrorContains(t, err, "native role version history is not active")
	require.Zero(t, historyQueries.Load())
}

func TestListRoleVersionsRejectsOverflowBeforeDatabaseIO(t *testing.T) {
	svc := newRoleServiceForTest(t, Options{})
	var queries atomic.Int64
	require.NoError(t, svc.store.DB().Callback().Query().Before("gorm:query").Register("test:role_history_zero_io", func(*gorm.DB) {
		queries.Add(1)
	}))

	_, err := svc.ListRoleVersions(context.Background(), "wsp_1", "usr_1", "role_1", math.MaxInt, 50)
	require.Error(t, err)
	require.Zero(t, queries.Load())
}
