package testkit

import (
	"context"
	"database/sql"
	"testing"

	"github.com/tidbcloud/AgentTeam/internal/coredb/testkit/tidbruntime"
)

type TiDBTestRuntime string

const (
	TiDBTestRuntimeFullCluster TiDBTestRuntime = TiDBTestRuntime(tidbruntime.TiDBTestRuntimeFullCluster)
	TiDBTestRuntimeUnistore    TiDBTestRuntime = TiDBTestRuntime(tidbruntime.TiDBTestRuntimeUnistore)
)

func toRuntime(runtime TiDBTestRuntime) tidbruntime.TiDBTestRuntime {
	return tidbruntime.TiDBTestRuntime(runtime)
}

// SkipReason returns the reason for a skippable integration-test setup error.
func SkipReason(err error) (string, bool) {
	return tidbruntime.SkipReason(err)
}

// StartIsolatedTiDB returns a fresh TiDB database DSN created from the active test runtime.
func StartIsolatedTiDB(t *testing.T) string {
	return tidbruntime.StartIsolatedTiDB(t)
}

// StartInitializedTiDB returns a fresh TiDB database DSN after applying the current schema.
func StartInitializedTiDB(t *testing.T) string {
	return tidbruntime.StartInitializedTiDB(t)
}

// StartInitializedTiDBWithCleanup returns a fresh TiDB database DSN and an explicit cleanup function.
func StartInitializedTiDBWithCleanup(ctx context.Context) (string, func(context.Context) error, error) {
	return tidbruntime.StartInitializedTiDBWithCleanup(ctx)
}

// OpenTiDB opens and pings a TiDB database for tests.
func OpenTiDB(t *testing.T, dsn string) *sql.DB {
	return tidbruntime.OpenTiDB(t, dsn)
}

// OpenTiDBContext opens and pings a TiDB database for package-level fixtures.
func OpenTiDBContext(ctx context.Context, dsn string) (*sql.DB, error) {
	return tidbruntime.OpenTiDBContext(ctx, dsn)
}

// PrepareMigratedTiDBTemplate ensures a reusable migrated TiDB template database exists.
func PrepareMigratedTiDBTemplate(ctx context.Context, rootDSN string) (string, error) {
	return tidbruntime.PrepareMigratedTiDBTemplate(ctx, rootDSN)
}

// StartUnistoreTiDBWithCleanup starts a local tidb-server backed by unistore.
func StartUnistoreTiDBWithCleanup(ctx context.Context) (string, func(context.Context) error, error) {
	return tidbruntime.StartUnistoreTiDBWithCleanup(ctx)
}

// StartTiDBRuntimeWithCleanup starts the requested root TiDB runtime.
func StartTiDBRuntimeWithCleanup(ctx context.Context, runtime TiDBTestRuntime) (string, func(context.Context) error, error) {
	return tidbruntime.StartTiDBRuntimeWithCleanup(ctx, toRuntime(runtime))
}

// StartInitializedTiDBWithRootDSN returns a migrated isolated TiDB database DSN on the provided root runtime.
func StartInitializedTiDBWithRootDSN(t *testing.T, rootDSN string) string {
	return tidbruntime.StartInitializedTiDBWithRootDSN(t, rootDSN)
}

// StartInitializedTiDBWithRootDSNAndCleanup returns a migrated isolated TiDB database DSN on the provided root runtime.
func StartInitializedTiDBWithRootDSNAndCleanup(ctx context.Context, rootDSN string) (string, func(context.Context) error, error) {
	return tidbruntime.StartInitializedTiDBWithRootDSNAndCleanup(ctx, rootDSN)
}

// StartInitializedTiDBWithRuntime returns a migrated isolated TiDB database DSN on the requested runtime.
func StartInitializedTiDBWithRuntime(t *testing.T, runtime TiDBTestRuntime) string {
	return tidbruntime.StartInitializedTiDBWithRuntime(t, toRuntime(runtime))
}

// StartInitializedTiDBWithRuntimeAndCleanup returns a migrated isolated TiDB database DSN on the requested runtime.
func StartInitializedTiDBWithRuntimeAndCleanup(ctx context.Context, runtime TiDBTestRuntime) (string, func(context.Context) error, error) {
	return tidbruntime.StartInitializedTiDBWithRuntimeAndCleanup(ctx, toRuntime(runtime))
}

// TiDBRuntimeFixture owns one package-level TiDB root runtime.
type TiDBRuntimeFixture struct {
	inner *tidbruntime.TiDBRuntimeFixture
}

func NewTiDBRuntimeFixture(runtime TiDBTestRuntime) *TiDBRuntimeFixture {
	return &TiDBRuntimeFixture{inner: tidbruntime.NewTiDBRuntimeFixture(toRuntime(runtime))}
}

func (fixture *TiDBRuntimeFixture) RootDSN(t testing.TB) string {
	if fixture == nil || fixture.inner == nil {
		t.Fatal("tidb runtime fixture is nil")
	}
	return fixture.inner.RootDSN(t)
}

func (fixture *TiDBRuntimeFixture) Cleanup(ctx context.Context) error {
	if fixture == nil || fixture.inner == nil {
		return nil
	}
	return fixture.inner.Cleanup(ctx)
}

func RunTestsWithTiDBRuntimeFixture(m *testing.M, name string, fixture *TiDBRuntimeFixture) int {
	if fixture == nil {
		return tidbruntime.RunTestsWithTiDBRuntimeFixture(m, name, nil)
	}
	return tidbruntime.RunTestsWithTiDBRuntimeFixture(m, name, fixture.inner)
}
