package database

import (
	"testing"
	"time"

	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/AgentTeam/internal/store/content"
)

func TestContentAuthorityMigrationKeepsOnlyExactNativeBindings(t *testing.T) {
	db, err := open(Config{DSN: "file:content_authority_one_way_upgrade?mode=memory&cache=shared"}, false)
	require.NoError(t, err)
	t.Cleanup(func() { require.NoError(t, Close(db)) })
	require.NoError(t, ensureSchemaMigrationsTable(db))

	migrations, err := readAutomationMigrations()
	require.NoError(t, err)
	for _, migration := range migrations {
		if migration.Version != "0024" {
			continue
		}
		require.NoError(t, executeAutomationMigration(db, migration))
		require.NoError(t, recordAutomationMigration(db, migration))
	}

	now := time.Date(2026, 8, 21, 14, 0, 0, 0, time.UTC)
	for _, authority := range []content.Authority{
		{ID: "cta_legacy", WorkspaceID: "wsp_1", Domain: "skill", BindingKey: "skl_legacy", State: content.AuthorityStateLegacyActive, Generation: 1, UpdatedBy: "old", CreatedAt: now, UpdatedAt: now},
		{ID: "cta_shadow", WorkspaceID: "wsp_1", Domain: "skill", BindingKey: "skl_shadow", State: "shadow_verified", Generation: 2, UpdatedBy: "old", CreatedAt: now, UpdatedAt: now},
		{ID: "cta_fenced_after_native", WorkspaceID: "wsp_1", Domain: "skill", BindingKey: "skl_fenced_after_native", State: "write_fenced", Generation: 4, Checkpoint: "checkpoint-after-native", UpdatedBy: "old", CreatedAt: now, UpdatedAt: now},
		{ID: "cta_fenced_before_native", WorkspaceID: "wsp_1", Domain: "skill", BindingKey: "skl_fenced_before_native", State: "write_fenced", Generation: 3, Checkpoint: "checkpoint-before-native", UpdatedBy: "old", CreatedAt: now, UpdatedAt: now},
		{ID: "cta_wildcard", WorkspaceID: "wsp_1", Domain: "skill", BindingKey: content.AuthorityDomainDefaultBinding, State: content.AuthorityStateNativeActive, Generation: 1, UpdatedBy: "old", CreatedAt: now, UpdatedAt: now},
		{ID: "cta_native", WorkspaceID: "wsp_1", Domain: "skill", BindingKey: "skl_native", State: content.AuthorityStateNativeActive, Generation: 3, UpdatedBy: "old", CreatedAt: now, UpdatedAt: now},
	} {
		require.NoError(t, db.Create(&authority).Error)
	}
	require.NoError(t, db.Exec(`UPDATE content_authorities
SET native_activated = TRUE, checkpoint = 'checkpoint-after-native'
WHERE id = 'cta_fenced_after_native'`).Error)
	var oldCheckpoint string
	require.NoError(t, db.Raw(`SELECT checkpoint FROM content_authorities WHERE id = 'cta_fenced_after_native'`).Scan(&oldCheckpoint).Error)
	require.Equal(t, "checkpoint-after-native", oldCheckpoint)
	require.NoError(t, db.Exec(`INSERT INTO content_authority_writers
  (id, workspace_id, domain, binding_key, state, generation, created_at)
  VALUES ('caw_1', 'wsp_1', 'skill', 'skl_legacy', 'legacy_active', 1, ?)`, now).Error)
	require.NoError(t, db.Exec(`INSERT INTO content_authority_recovery_points
  (id, workspace_id, domain, binding_key, authority_generation, snapshot_digest, state, prepared_by, verified_by, created_at)
  VALUES ('car_1', 'wsp_1', 'skill', 'skl_native', 3, ?, 'verified', 'old', 'old-2', ?)`,
		"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", now).Error)

	require.NoError(t, Migrate(db))
	require.False(t, db.Migrator().HasColumn("content_authorities", "native_activated"))
	require.False(t, db.Migrator().HasColumn("content_authorities", "recovery_point_id"))
	assertMigratedAuthority := func() {
		var authority content.Authority
		require.NoError(t, db.First(&authority, "id = ?", "cta_fenced_after_native").Error)
		require.Equal(t, content.AuthorityStateNativeActive, authority.State)
		require.Equal(t, uint64(4), authority.Generation)
		require.Equal(t, "checkpoint-after-native", authority.Checkpoint)
	}
	assertMigratedAuthority()

	// Once 0025 has removed its legacy markers, the next startup must use the
	// normal current-schema AutoMigrate path without losing activation proof.
	require.NoError(t, Migrate(db))
	assertMigratedAuthority()

	// A failed deployment can rerun 0025 before its schema-migration record is
	// committed. Its normalization and cleanup must therefore stay idempotent.
	var retried bool
	for _, migration := range migrations {
		if migration.Version != "0025" {
			continue
		}
		require.NoError(t, executeAutomationMigration(db, migration))
		require.NoError(t, executeAutomationMigration(db, migration))
		retried = true
	}
	require.True(t, retried)
	require.False(t, db.Migrator().HasTable("content_authority_writers"))
	require.False(t, db.Migrator().HasTable("content_authority_recovery_points"))

	var rows []content.Authority
	require.NoError(t, db.Order("id").Find(&rows).Error)
	require.Len(t, rows, 2)
	require.Equal(t, "cta_fenced_after_native", rows[0].ID)
	require.Equal(t, content.AuthorityStateNativeActive, rows[0].State)
	require.Equal(t, uint64(4), rows[0].Generation)
	require.Equal(t, "checkpoint-after-native", rows[0].Checkpoint)
	require.Equal(t, "cta_native", rows[1].ID)
	require.Equal(t, content.AuthorityStateNativeActive, rows[1].State)
	require.Equal(t, uint64(3), rows[1].Generation)
}

func TestContentAuthoritySimplificationSupportsFreshSchemaAndRetry(t *testing.T) {
	db, err := open(Config{DSN: "file:content_authority_one_way_fresh?mode=memory&cache=shared"}, false)
	require.NoError(t, err)
	t.Cleanup(func() { require.NoError(t, Close(db)) })
	require.NoError(t, Migrate(db))
	require.False(t, db.Migrator().HasColumn("content_authorities", "native_activated"))
	require.False(t, db.Migrator().HasColumn("content_authorities", "recovery_point_id"))
	require.NoError(t, Migrate(db))

	now := time.Date(2026, 8, 21, 15, 0, 0, 0, time.UTC)
	require.NoError(t, db.Create(&content.Authority{
		ID: "cta_native", WorkspaceID: "wsp_1", Domain: "skill", BindingKey: "skl_native",
		State: content.AuthorityStateNativeActive, Generation: 2, Checkpoint: "import:final",
		UpdatedBy: "operator", CreatedAt: now, UpdatedAt: now,
	}).Error)

	migrations, err := readAutomationMigrations()
	require.NoError(t, err)
	var retried bool
	for _, migration := range migrations {
		if migration.Version != "0025" {
			continue
		}
		require.NoError(t, executeAutomationMigration(db, migration))
		require.NoError(t, executeAutomationMigration(db, migration))
		retried = true
	}
	require.True(t, retried)

	var authority content.Authority
	require.NoError(t, db.First(&authority, "id = ?", "cta_native").Error)
	require.Equal(t, content.AuthorityStateNativeActive, authority.State)
	require.Equal(t, uint64(2), authority.Generation)
	require.Equal(t, "import:final", authority.Checkpoint)
}
