package server

import (
	"bytes"
	"context"
	"crypto/rand"
	"errors"
	"testing"
	"time"

	"github.com/mem9-ai/drive9/pkg/encrypt"
	"github.com/mem9-ai/drive9/pkg/meta"
	"github.com/mem9-ai/drive9/pkg/tenant"
	tenantschema "github.com/mem9-ai/drive9/pkg/tenant/schema"
	"github.com/mem9-ai/drive9/pkg/testtidb"
)

func newDeletingPoolResumeServer(t *testing.T) (*Server, *meta.Store) {
	t.Helper()
	metaStore, err := meta.Open(testDSN)
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { _ = metaStore.Close() })
	testtidb.ResetMetaDB(t, metaStore.DB())
	srv := &Server{meta: metaStore}
	t.Cleanup(srv.Close)
	return srv, metaStore
}

func makeManagedSharedDBReadyForPurge(t *testing.T, ctx context.Context, db *testDBInfo, dbID int64) {
	t.Helper()
	passwordCipher, err := db.Pool.Encrypt(ctx, []byte(db.DBPass))
	if err != nil {
		t.Fatalf("encrypt shared DB password: %v", err)
	}
	if _, err := db.Meta.DB().ExecContext(ctx, `UPDATE db_pool
		SET status = ?, db_host = ?, db_port = ?, db_user = ?, db_password = ?, db_name = ?, schema_version = ?
		WHERE db_id = ?`, meta.SharedDBStatusActive, db.DBHost, db.DBPort, db.DBUser, passwordCipher,
		db.DBName, tenantschema.CurrentSharedTiDBSchemaVersion, dbID); err != nil {
		t.Fatalf("make managed shared DB ready: %v", err)
	}
}

func TestResumeDeletingTenantPoolFinalizesEmptyPool(t *testing.T) {
	srv, metaStore := newDeletingPoolResumeServer(t)
	ctx := context.Background()
	pool := &meta.TenantPool{PoolID: "pool-resume-empty", OrganizationID: "org-resume-empty",
		Size: 0, Status: meta.TenantPoolDeleting, CreatedAt: time.Now().UTC(), UpdatedAt: time.Now().UTC()}
	if err := metaStore.CreateTenantPool(ctx, pool); err != nil {
		t.Fatal(err)
	}

	srv.resumeDeletingTenantPool(ctx, pool)

	if _, err := metaStore.GetTenantPoolByID(ctx, pool.PoolID); !errors.Is(err, meta.ErrNotFound) {
		t.Fatalf("pool after resume = %v, want not found", err)
	}
}

func TestResumeDeletingTenantPoolDropsDeletedFreeNativeBinding(t *testing.T) {
	srv, metaStore := newDeletingPoolResumeServer(t)
	ctx := context.Background()
	now := time.Now().UTC()
	pool := &meta.TenantPool{PoolID: "pool-resume-orphan", OrganizationID: "org-resume-orphan",
		Size: 1, Status: meta.TenantPoolDeleting, CreatedAt: now, UpdatedAt: now}
	if err := metaStore.CreateTenantPool(ctx, pool); err != nil {
		t.Fatal(err)
	}
	if err := metaStore.InsertTenant(ctx, &meta.Tenant{
		ID: "orphan-free-native", Status: meta.TenantDeleted, Provider: tenant.ProviderTiDBCloudNative,
		DBPasswordCipher: []byte{}, CreatedAt: now, UpdatedAt: now,
	}); err != nil {
		t.Fatalf("InsertTenant: %v", err)
	}
	if err := metaStore.UpsertTenantTiDBCloudOrgBinding(ctx, &meta.TenantTiDBCloudOrgBinding{
		TenantID: "orphan-free-native", OrganizationID: pool.OrganizationID, ClusterID: "cluster-orphan",
		PoolID: pool.PoolID, PoolStatus: meta.TenantPoolBindingFree, CreatedAt: now, UpdatedAt: now,
	}); err != nil {
		t.Fatalf("UpsertTenantTiDBCloudOrgBinding: %v", err)
	}

	srv.resumeDeletingTenantPool(ctx, pool)

	if _, err := metaStore.GetTenantPoolByID(ctx, pool.PoolID); !errors.Is(err, meta.ErrNotFound) {
		t.Fatalf("pool after resume = %v, want not found", err)
	}
	if _, err := metaStore.GetTenantTiDBCloudOrgBinding(ctx, "orphan-free-native"); !errors.Is(err, meta.ErrNotFound) {
		t.Fatalf("orphan binding after resume = %v, want not found", err)
	}
}

func TestResumeDeletingTenantPoolPreservesUnconfirmedFreeNativeDelete(t *testing.T) {
	srv, metaStore := newDeletingPoolResumeServer(t)
	ctx := context.Background()
	now := time.Now().UTC()
	const tenantID = "unconfirmed-free-native"
	pool := &meta.TenantPool{PoolID: "pool-resume-unconfirmed", OrganizationID: "org-resume-unconfirmed",
		Size: 1, Status: meta.TenantPoolDeleting, CreatedAt: now, UpdatedAt: now}
	if err := metaStore.CreateTenantPool(ctx, pool); err != nil {
		t.Fatal(err)
	}
	if err := metaStore.InsertTenant(ctx, &meta.Tenant{
		ID: tenantID, Status: meta.TenantDeleting, Provider: tenant.ProviderTiDBCloudNative,
		StorageNamespaceID: tenantID + "-ns", DBPasswordCipher: []byte{}, CreatedAt: now, UpdatedAt: now,
	}); err != nil {
		t.Fatal(err)
	}
	if err := metaStore.UpsertStorageNamespace(ctx, &meta.StorageNamespace{
		ID: tenantID + "-ns", OwnerTenantID: tenantID, Backend: "local", Prefix: "tenant/" + tenantID,
		State: meta.StorageNamespaceActive, CreatedAt: now, UpdatedAt: now,
	}); err != nil {
		t.Fatal(err)
	}
	if err := metaStore.UpsertTenantTiDBCloudOrgBinding(ctx, &meta.TenantTiDBCloudOrgBinding{
		TenantID: tenantID, OrganizationID: pool.OrganizationID, ClusterID: "cluster-unconfirmed",
		PoolID: pool.PoolID, PoolStatus: meta.TenantPoolBindingFree, CreatedAt: now, UpdatedAt: now,
	}); err != nil {
		t.Fatal(err)
	}
	srv.resumeDeletingTenantPool(ctx, pool)

	if _, err := metaStore.GetTenantPoolByID(ctx, pool.PoolID); err != nil {
		t.Fatalf("pool after resume = %v, want present until credentialed retry", err)
	}
	binding, err := metaStore.GetTenantTiDBCloudOrgBinding(ctx, tenantID)
	if err != nil {
		t.Fatalf("binding after resume = %v, want present", err)
	}
	if binding.PoolID != pool.PoolID || binding.PoolStatus != meta.TenantPoolBindingFree {
		t.Fatalf("binding after resume = %+v, want untouched", binding)
	}
}

func TestResumeDeletingTenantPoolPurgesInterruptedSharedMember(t *testing.T) {
	db := newTestDBInfo(t)
	metaStore := db.Meta
	testtidb.ResetMetaDB(t, metaStore.DB())
	installServerSharedSchema(t, metaStore.DB())
	poolManager := db.Pool
	ctx := context.Background()
	now := time.Now().UTC()

	// Simulate a pool delete interrupted mid-purge: the pool is deleting, one
	// shared free member is still fully provisioned (fs_id, placement,
	// membership) and was never touched.
	pool := &meta.TenantPool{PoolID: "pool-resume-interrupted", OrganizationID: "org-resume-interrupted",
		Size: 1, Status: meta.TenantPoolDeleting, CreatedAt: now, UpdatedAt: now}
	if err := metaStore.CreateTenantPool(ctx, pool); err != nil {
		t.Fatal(err)
	}
	spendingLimit := meta.MaxTiDBCloudSpendingLimit
	dbID, err := metaStore.CreateManagedSharedDBPool(ctx, &meta.SharedDB{
		TiDBCloudOrganizationID: pool.OrganizationID, ProvisioningKey: bytes.Repeat([]byte{2}, 32),
		CloudProvider: "aws", Region: "us-east-1", MaxTenants: 100, SpendingLimit: &spendingLimit,
	})
	if err != nil {
		t.Fatalf("CreateManagedSharedDBPool: %v", err)
	}
	makeManagedSharedDBReadyForPurge(t, ctx, db, dbID)
	tenantID := "shared-interrupted-member"
	if err := metaStore.InsertTenant(ctx, &meta.Tenant{ID: tenantID, Status: meta.TenantActive,
		Provider: tenant.ProviderTiDBCloudNativeShared, DBPasswordCipher: []byte{}, SchemaVersion: 1,
		CreatedAt: now, UpdatedAt: now}); err != nil {
		t.Fatalf("InsertTenant: %v", err)
	}
	fsID, err := metaStore.EnsureFsID(ctx, tenantID)
	if err != nil {
		t.Fatalf("EnsureFsID: %v", err)
	}
	if err := metaStore.CompleteSharedTenantPoolMember(ctx, tenantID, tenant.ProviderTiDBCloudNativeShared,
		&meta.TenantPlacement{FsID: fsID, DbID: dbID, Placement: meta.PlacementShared, SchemaShape: meta.SchemaShapeShared},
		&meta.TenantPoolMembership{TenantID: tenantID, TiDBCloudOrganizationID: pool.OrganizationID,
			PoolID: pool.PoolID, PoolStatus: meta.TenantPoolBindingFree}); err != nil {
		t.Fatalf("CompleteSharedTenantPoolMember: %v", err)
	}

	srv := &Server{meta: metaStore, pool: poolManager, sharedDBReopenRatio: DefaultSharedDBReopenRatio}
	t.Cleanup(srv.Close)
	srv.resumeDeletingTenantPool(ctx, pool)

	if _, err := metaStore.GetTenantPoolByID(ctx, pool.PoolID); !errors.Is(err, meta.ErrNotFound) {
		t.Fatalf("pool after resume = %v, want not found", err)
	}
	got, err := metaStore.GetTenant(ctx, tenantID)
	if err != nil {
		t.Fatalf("GetTenant: %v", err)
	}
	if got.Status != meta.TenantDeleted {
		t.Fatalf("interrupted shared member status = %s, want %s", got.Status, meta.TenantDeleted)
	}
	if _, err := metaStore.GetTenantPoolMembership(ctx, tenantID); !errors.Is(err, meta.ErrNotFound) {
		t.Fatalf("membership after resume = %v, want not found", err)
	}
}

func TestResumeDeletingTenantPoolContinuesDeletingSharedMember(t *testing.T) {
	db := newTestDBInfo(t)
	metaStore := db.Meta
	testtidb.ResetMetaDB(t, metaStore.DB())
	installServerSharedSchema(t, metaStore.DB())
	poolManager := db.Pool
	ctx := context.Background()
	now := time.Now().UTC()

	pool := &meta.TenantPool{PoolID: "pool-resume-deleting-member", OrganizationID: "org-resume-deleting-member",
		Size: 1, Status: meta.TenantPoolDeleting, CreatedAt: now, UpdatedAt: now}
	if err := metaStore.CreateTenantPool(ctx, pool); err != nil {
		t.Fatal(err)
	}
	spendingLimit := meta.MaxTiDBCloudSpendingLimit
	dbID, err := metaStore.CreateManagedSharedDBPool(ctx, &meta.SharedDB{
		TiDBCloudOrganizationID: pool.OrganizationID, ProvisioningKey: bytes.Repeat([]byte{4}, 32),
		CloudProvider: "aws", Region: "us-east-1", MaxTenants: 100, SpendingLimit: &spendingLimit,
	})
	if err != nil {
		t.Fatalf("CreateManagedSharedDBPool: %v", err)
	}
	makeManagedSharedDBReadyForPurge(t, ctx, db, dbID)
	const tenantID = "shared-deleting-member"
	if err := metaStore.InsertTenant(ctx, &meta.Tenant{
		ID: tenantID, Status: meta.TenantActive, Provider: tenant.ProviderTiDBCloudNativeShared,
		StorageNamespaceID: tenantID + "-ns", DBPasswordCipher: []byte{}, SchemaVersion: 1,
		CreatedAt: now, UpdatedAt: now,
	}); err != nil {
		t.Fatalf("InsertTenant: %v", err)
	}
	if err := metaStore.UpsertStorageNamespace(ctx, &meta.StorageNamespace{
		ID: tenantID + "-ns", OwnerTenantID: tenantID, Backend: "local", Bucket: "bucket",
		Prefix: "tenant/" + tenantID, State: meta.StorageNamespaceActive, CreatedAt: now, UpdatedAt: now,
	}); err != nil {
		t.Fatalf("UpsertStorageNamespace: %v", err)
	}
	fsID, err := metaStore.EnsureFsID(ctx, tenantID)
	if err != nil {
		t.Fatalf("EnsureFsID: %v", err)
	}
	if err := metaStore.CompleteSharedTenantPoolMember(ctx, tenantID, tenant.ProviderTiDBCloudNativeShared,
		&meta.TenantPlacement{FsID: fsID, DbID: dbID, Placement: meta.PlacementShared, SchemaShape: meta.SchemaShapeShared},
		&meta.TenantPoolMembership{TenantID: tenantID, TiDBCloudOrganizationID: pool.OrganizationID,
			PoolID: pool.PoolID, PoolStatus: meta.TenantPoolBindingFree}); err != nil {
		t.Fatalf("CompleteSharedTenantPoolMember: %v", err)
	}
	tenantRow, err := metaStore.GetTenant(ctx, tenantID)
	if err != nil {
		t.Fatal(err)
	}
	ns, err := metaStore.GetStorageNamespace(ctx, tenantRow.StorageNamespaceID)
	if err != nil {
		t.Fatal(err)
	}
	updated, err := metaStore.MarkFreeSharedTenantPoolTenantDeletingWithDeleteJob(ctx, tenantID, tenantRow.Status,
		delayedTenantDeleteJob(tenantRow, ns))
	if err != nil || !updated {
		t.Fatalf("mark deleting: updated=%v err=%v", updated, err)
	}

	srv := &Server{meta: metaStore, pool: poolManager, sharedDBReopenRatio: DefaultSharedDBReopenRatio}
	t.Cleanup(srv.Close)
	srv.resumeDeletingTenantPool(ctx, pool)

	if _, err := metaStore.GetTenantPoolByID(ctx, pool.PoolID); !errors.Is(err, meta.ErrNotFound) {
		t.Fatalf("pool after resume = %v, want not found", err)
	}
	got, err := metaStore.GetTenant(ctx, tenantID)
	if err != nil {
		t.Fatal(err)
	}
	if got.Status != meta.TenantDeleting {
		t.Fatalf("tenant status = %s, want %s until object cleanup", got.Status, meta.TenantDeleting)
	}
	placement, err := metaStore.GetTenantPlacement(ctx, fsID)
	if err != nil {
		t.Fatalf("placement must remain as the purge-complete marker: %v", err)
	}
	if placement.Status != meta.PlacementStatusDeleting {
		t.Fatalf("placement status = %s, want %s", placement.Status, meta.PlacementStatusDeleting)
	}
	if _, err := metaStore.GetTenantPoolMembership(ctx, tenantID); !errors.Is(err, meta.ErrNotFound) {
		t.Fatalf("membership after purge completion = %v, want not found", err)
	}
	armed, err := metaStore.TenantDeleteJobArmed(ctx, tenantID)
	if err != nil {
		t.Fatal(err)
	}
	if !armed {
		t.Fatal("tenant delete job was not armed after shared purge completion")
	}
}

func TestResumeDeletingTenantPoolRollsBackFailedSharedPurge(t *testing.T) {
	metaStore, err := meta.Open(testDSN)
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { _ = metaStore.Close() })
	testtidb.ResetMetaDB(t, metaStore.DB())
	master := make([]byte, 32)
	if _, err := rand.Read(master); err != nil {
		t.Fatal(err)
	}
	enc, err := encrypt.NewLocalAESEncryptor(master)
	if err != nil {
		t.Fatal(err)
	}
	poolManager := tenant.NewPool(tenant.PoolConfig{S3Dir: mustTempDir(t), PublicURL: "http://localhost"}, enc)
	t.Cleanup(poolManager.Close)
	poolManager.SetMetaStore(metaStore)
	ctx := context.Background()
	now := time.Now().UTC()

	pool := &meta.TenantPool{PoolID: "pool-resume-purge-fails", OrganizationID: "org-resume-purge-fails",
		Size: 1, Status: meta.TenantPoolDeleting, CreatedAt: now, UpdatedAt: now}
	if err := metaStore.CreateTenantPool(ctx, pool); err != nil {
		t.Fatal(err)
	}
	tenantID := "shared-purge-fails-member"
	if err := metaStore.InsertTenant(ctx, &meta.Tenant{ID: tenantID, Status: meta.TenantActive,
		Provider: tenant.ProviderTiDBCloudNativeShared, StorageNamespaceID: tenantID + "-ns",
		DBPasswordCipher: []byte{}, SchemaVersion: 1, CreatedAt: now, UpdatedAt: now}); err != nil {
		t.Fatalf("InsertTenant: %v", err)
	}
	if err := metaStore.UpsertStorageNamespace(ctx, &meta.StorageNamespace{
		ID: tenantID + "-ns", OwnerTenantID: tenantID, Backend: "local",
		Bucket: "bucket", Prefix: "tenant/" + tenantID, State: meta.StorageNamespaceActive,
		CreatedAt: now, UpdatedAt: now,
	}); err != nil {
		t.Fatalf("UpsertStorageNamespace: %v", err)
	}
	spendingLimit := meta.MaxTiDBCloudSpendingLimit
	dbID, err := metaStore.CreateManagedSharedDBPool(ctx, &meta.SharedDB{
		TiDBCloudOrganizationID: pool.OrganizationID, ProvisioningKey: bytes.Repeat([]byte{3}, 32),
		CloudProvider: "aws", Region: "us-east-1", MaxTenants: 100, SpendingLimit: &spendingLimit,
	})
	if err != nil {
		t.Fatalf("CreateManagedSharedDBPool: %v", err)
	}
	fsID, err := metaStore.EnsureFsID(ctx, tenantID)
	if err != nil {
		t.Fatalf("EnsureFsID: %v", err)
	}
	if err := metaStore.CompleteSharedTenantPoolMember(ctx, tenantID, tenant.ProviderTiDBCloudNativeShared,
		&meta.TenantPlacement{FsID: fsID, DbID: dbID, Placement: meta.PlacementShared, SchemaShape: meta.SchemaShapeShared},
		&meta.TenantPoolMembership{TenantID: tenantID, TiDBCloudOrganizationID: pool.OrganizationID,
			PoolID: pool.PoolID, PoolStatus: meta.TenantPoolBindingFree}); err != nil {
		t.Fatalf("CompleteSharedTenantPoolMember: %v", err)
	}
	// Remove the shared DB row so the purge fails early — before any
	// irreversible step — and the reconciler must roll the tenant back with
	// its cleanup job dropped.
	if _, err := metaStore.DB().ExecContext(ctx, `DELETE FROM db_pool WHERE db_id = ?`, dbID); err != nil {
		t.Fatalf("delete db pool row: %v", err)
	}

	srv := &Server{meta: metaStore, pool: poolManager, sharedDBReopenRatio: DefaultSharedDBReopenRatio}
	t.Cleanup(srv.Close)
	preDelete, err := metaStore.GetTenant(ctx, tenantID)
	if err != nil {
		t.Fatalf("GetTenant before resume: %v", err)
	}
	srv.resumeDeletingTenantPool(ctx, pool)

	got, err := metaStore.GetTenant(ctx, tenantID)
	if err != nil {
		t.Fatalf("GetTenant: %v", err)
	}
	if got.Status != preDelete.Status {
		t.Fatalf("tenant status after failed purge = %s, want %s (rolled back)", got.Status, preDelete.Status)
	}
	exists, err := metaStore.TenantDeleteJobExists(ctx, tenantID)
	if err != nil {
		t.Fatal(err)
	}
	if exists {
		t.Fatal("cleanup job survived the rollback of a failed shared purge")
	}
	membership, err := metaStore.GetTenantPoolMembership(ctx, tenantID)
	if err != nil {
		t.Fatalf("GetTenantPoolMembership: %v", err)
	}
	if membership.PoolStatus != meta.TenantPoolBindingFree {
		t.Fatalf("membership after rollback = %+v, want still free", membership)
	}
	if _, err := metaStore.GetTenantPoolByID(ctx, pool.PoolID); err != nil {
		t.Fatalf("pool after failed purge = %v, want present", err)
	}
}

func TestRollbackFreeSharedPoolTenantDeleteStopsWhenDeleteAlreadyOwnedOrPlacementRemoved(t *testing.T) {
	metaStore, err := meta.Open(testDSN)
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { _ = metaStore.Close() })
	testtidb.ResetMetaDB(t, metaStore.DB())
	ctx := context.Background()
	now := time.Now().UTC()
	const tenantID = "shared-delete-past-placement"
	if err := metaStore.InsertTenant(ctx, &meta.Tenant{
		ID: tenantID, Status: meta.TenantActive, Provider: tenant.ProviderTiDBCloudNativeShared,
		StorageNamespaceID: tenantID + "-ns", DBPasswordCipher: []byte{}, CreatedAt: now, UpdatedAt: now,
	}); err != nil {
		t.Fatal(err)
	}
	if err := metaStore.UpsertStorageNamespace(ctx, &meta.StorageNamespace{
		ID: tenantID + "-ns", OwnerTenantID: tenantID, Backend: "local",
		Prefix: "tenant/" + tenantID, State: meta.StorageNamespaceActive, CreatedAt: now, UpdatedAt: now,
	}); err != nil {
		t.Fatal(err)
	}
	if err := metaStore.CreateTenantPool(ctx, &meta.TenantPool{
		PoolID: "pool-past-placement", OrganizationID: "org-past-placement", Size: 1,
		Status: meta.TenantPoolDeleting, CreatedAt: now, UpdatedAt: now,
	}); err != nil {
		t.Fatal(err)
	}
	dbID, err := metaStore.RegisterSharedDB(ctx, &meta.SharedDB{
		TiDBCloudOrganizationID: "org-past-placement", Host: "shared.example.com", Port: 4000,
		User: "root", PasswordCipher: []byte("cipher"), Name: "past_placement", MaxTenants: 100,
	})
	if err != nil {
		t.Fatal(err)
	}
	fsID, err := metaStore.EnsureFsID(ctx, tenantID)
	if err != nil {
		t.Fatal(err)
	}
	if err := metaStore.CompleteSharedTenantPoolMember(ctx, tenantID, tenant.ProviderTiDBCloudNativeShared,
		&meta.TenantPlacement{FsID: fsID, DbID: dbID, Placement: meta.PlacementShared, SchemaShape: meta.SchemaShapeShared},
		&meta.TenantPoolMembership{TenantID: tenantID, TiDBCloudOrganizationID: "org-past-placement",
			PoolID: "pool-past-placement", PoolStatus: meta.TenantPoolBindingFree}); err != nil {
		t.Fatal(err)
	}
	tenantRow, err := metaStore.GetTenant(ctx, tenantID)
	if err != nil {
		t.Fatal(err)
	}
	ns, err := metaStore.GetStorageNamespace(ctx, tenantRow.StorageNamespaceID)
	if err != nil {
		t.Fatal(err)
	}
	updated, err := metaStore.MarkFreeSharedTenantPoolTenantDeletingWithDeleteJob(ctx, tenantID, tenantRow.Status,
		delayedTenantDeleteJob(tenantRow, ns))
	if err != nil {
		t.Fatal(err)
	}
	if !updated {
		t.Fatal("delete mark not applied")
	}
	deletingRow, err := metaStore.GetTenant(ctx, tenantID)
	if err != nil {
		t.Fatal(err)
	}
	srv := &Server{meta: metaStore}
	srv.rollbackFreeSharedPoolTenantDelete(ctx, deletingRow)
	if exists, err := metaStore.TenantDeleteJobExists(ctx, tenantID); err != nil || !exists {
		t.Fatalf("cleanup job after already-owned rollback: exists=%v err=%v, want true/nil", exists, err)
	}
	ns, err = metaStore.GetStorageNamespace(ctx, tenantRow.StorageNamespaceID)
	if err != nil {
		t.Fatal(err)
	}
	if ns.State != meta.StorageNamespaceDeleting {
		t.Fatalf("namespace after already-owned rollback = %s, want %s", ns.State, meta.StorageNamespaceDeleting)
	}
	if _, err := metaStore.DB().ExecContext(ctx, `DELETE FROM tenant_placements WHERE fs_id = ?`, fsID); err != nil {
		t.Fatal(err)
	}

	srv.rollbackFreeSharedPoolTenantDelete(ctx, tenantRow)

	got, err := metaStore.GetTenant(ctx, tenantID)
	if err != nil {
		t.Fatal(err)
	}
	if got.Status != meta.TenantDeleting {
		t.Fatalf("tenant status = %s, want %s after placement removal", got.Status, meta.TenantDeleting)
	}
	exists, err := metaStore.TenantDeleteJobExists(ctx, tenantID)
	if err != nil {
		t.Fatal(err)
	}
	if !exists {
		t.Fatal("cleanup job was removed after point of no return")
	}
}

func TestResumeDeletingTenantPoolLeavesPoolWithLiveFreeNativeMember(t *testing.T) {
	srv, metaStore := newDeletingPoolResumeServer(t)
	ctx := context.Background()
	now := time.Now().UTC()
	pool := &meta.TenantPool{PoolID: "pool-resume-blocked", OrganizationID: "org-resume-blocked",
		Size: 1, Status: meta.TenantPoolDeleting, CreatedAt: now, UpdatedAt: now}
	if err := metaStore.CreateTenantPool(ctx, pool); err != nil {
		t.Fatal(err)
	}
	if err := metaStore.InsertTenant(ctx, &meta.Tenant{
		ID: "live-free-native", Status: meta.TenantActive, Provider: tenant.ProviderTiDBCloudNative,
		DBPasswordCipher: []byte{}, CreatedAt: now, UpdatedAt: now,
	}); err != nil {
		t.Fatalf("InsertTenant: %v", err)
	}
	if err := metaStore.UpsertTenantTiDBCloudOrgBinding(ctx, &meta.TenantTiDBCloudOrgBinding{
		TenantID: "live-free-native", OrganizationID: pool.OrganizationID, ClusterID: "cluster-live",
		PoolID: pool.PoolID, PoolStatus: meta.TenantPoolBindingFree, CreatedAt: now, UpdatedAt: now,
	}); err != nil {
		t.Fatalf("UpsertTenantTiDBCloudOrgBinding: %v", err)
	}

	srv.resumeDeletingTenantPool(ctx, pool)

	if _, err := metaStore.GetTenantPoolByID(ctx, pool.PoolID); err != nil {
		t.Fatalf("pool after resume = %v, want present (native free members need caller credentials)", err)
	}
	binding, err := metaStore.GetTenantTiDBCloudOrgBinding(ctx, "live-free-native")
	if err != nil {
		t.Fatalf("GetTenantTiDBCloudOrgBinding: %v", err)
	}
	if binding.PoolID != pool.PoolID || binding.PoolStatus != meta.TenantPoolBindingFree {
		t.Fatalf("live free binding after resume = %+v, want untouched", binding)
	}
}
