package mysql

import (
	"context"
	"testing"

	"hyapp/internal/testutil/mysqlschema"
)

// 已存在的旧 room_outbox 表（没有房间维度索引）必须由 Migrate 的 ensure 链补出
// idx_room_outbox_room_event，覆盖线上 mysql_auto_migrate=true 时的升级路径。
func TestMigrateBackfillsRoomOutboxRoomEventIndex(t *testing.T) {
	schema := mysqlschema.New(t, mysqlschema.Config{
		EnvVar:         "ROOM_SERVICE_MYSQL_TEST_DSN",
		InitDBPath:     mysqlschema.InitDBPath(t, mysqlschema.CallerFile(t, 1), "..", "..", "..", "deploy", "mysql", "initdb", "001_room_service.sql"),
		DatabasePrefix: "hyapp_room_idx_test",
	})
	ctx := context.Background()
	if _, err := schema.DB.ExecContext(ctx, `ALTER TABLE room_outbox DROP INDEX idx_room_outbox_room_event`); err != nil {
		t.Fatalf("drop index to simulate legacy table: %v", err)
	}

	repo, err := Open(ctx, schema.DSN, 4, 4)
	if err != nil {
		t.Fatalf("open repository: %v", err)
	}
	defer repo.Close()
	if err := repo.Migrate(ctx); err != nil {
		t.Fatalf("migrate: %v", err)
	}

	hasIndex, err := repo.indexExists(ctx, "room_outbox", "idx_room_outbox_room_event")
	if err != nil {
		t.Fatalf("check index: %v", err)
	}
	if !hasIndex {
		t.Fatal("Migrate did not backfill idx_room_outbox_room_event on an existing room_outbox table")
	}
}

// 旧版本 initdb/ensure 链把 idx_room_outbox_retry 建成了和 idx_room_outbox_pending 完全相同的列组合；
// Migrate 必须在 mysql_auto_migrate=true 时把这份重复索引删掉，消除多余写放大。
func TestMigrateDropsDuplicateRoomOutboxRetryIndex(t *testing.T) {
	schema := mysqlschema.New(t, mysqlschema.Config{
		EnvVar:         "ROOM_SERVICE_MYSQL_TEST_DSN",
		InitDBPath:     mysqlschema.InitDBPath(t, mysqlschema.CallerFile(t, 1), "..", "..", "..", "deploy", "mysql", "initdb", "001_room_service.sql"),
		DatabasePrefix: "hyapp_room_idx_test",
	})
	ctx := context.Background()
	if _, err := schema.DB.ExecContext(ctx, `ALTER TABLE room_outbox ADD INDEX idx_room_outbox_retry (app_code, status, next_retry_at_ms, created_at_ms, event_id)`); err != nil {
		t.Fatalf("add index to simulate legacy table: %v", err)
	}

	repo, err := Open(ctx, schema.DSN, 4, 4)
	if err != nil {
		t.Fatalf("open repository: %v", err)
	}
	defer repo.Close()
	if err := repo.Migrate(ctx); err != nil {
		t.Fatalf("migrate: %v", err)
	}

	hasIndex, err := repo.indexExists(ctx, "room_outbox", "idx_room_outbox_retry")
	if err != nil {
		t.Fatalf("check index: %v", err)
	}
	if hasIndex {
		t.Fatal("Migrate did not drop the duplicate idx_room_outbox_retry index")
	}
	hasPending, err := repo.indexExists(ctx, "room_outbox", "idx_room_outbox_pending")
	if err != nil {
		t.Fatalf("check pending index: %v", err)
	}
	if !hasPending {
		t.Fatal("idx_room_outbox_pending must survive the duplicate index cleanup")
	}
}

func TestMigrateBackfillsGiftV2SchemaOnExistingDatabase(t *testing.T) {
	schema := mysqlschema.New(t, mysqlschema.Config{
		EnvVar:         "ROOM_SERVICE_MYSQL_TEST_DSN",
		InitDBPath:     mysqlschema.InitDBPath(t, mysqlschema.CallerFile(t, 1), "..", "..", "..", "deploy", "mysql", "initdb", "001_room_service.sql"),
		DatabasePrefix: "hyapp_room_gift_v2_migrate",
	})
	ctx := context.Background()
	if _, err := schema.DB.ExecContext(ctx, `DROP TABLE room_gift_operations`); err != nil {
		t.Fatalf("drop gift operation table: %v", err)
	}
	if _, err := schema.DB.ExecContext(ctx, `ALTER TABLE room_command_log DROP COLUMN result_payload`); err != nil {
		t.Fatalf("drop result_payload: %v", err)
	}
	repo, err := Open(ctx, schema.DSN, 4, 4)
	if err != nil {
		t.Fatalf("open repository: %v", err)
	}
	defer repo.Close()
	if err := repo.Migrate(ctx); err != nil {
		t.Fatalf("migrate legacy gift schema: %v", err)
	}
	hasResult, err := repo.columnExists(ctx, "room_command_log", "result_payload")
	if err != nil || !hasResult {
		t.Fatalf("result_payload was not backfilled: exists=%v err=%v", hasResult, err)
	}
	var operationTableCount int
	if err := repo.db.QueryRowContext(ctx, `
		SELECT COUNT(*) FROM information_schema.TABLES
		WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'room_gift_operations'
	`).Scan(&operationTableCount); err != nil || operationTableCount != 1 {
		t.Fatalf("room_gift_operations was not created: count=%d err=%v", operationTableCount, err)
	}
	if _, _, err := repo.GetCommand(ctx, "missing-room", "missing-command"); err != nil {
		t.Fatalf("GetCommand must be usable immediately after auto migration: %v", err)
	}
}
