package db

import (
	"fmt"
	"slices"
	"sync/atomic"

	"github.com/tidbcloud/pkgv2/db"
	"github.com/tidbcloud/pkgv2/gormutil"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"github.com/uptrace/opentelemetry-go-extra/otelgorm"
	"gorm.io/gorm"
	"gorm.io/plugin/prometheus"

	"github.com/tidbcloud/tidb-management-service/serverless-global-service/pkg/config"
)

var (
	globalDB    *gorm.DB
	initialized atomic.Bool
)

func NewGormDB() *gorm.DB {
	if initialized.Swap(true) {
		return globalDB
	}

	conf := config.Global()

	// Only allow TLS config key to be one of the following values.
	// Currently, not support customized server CA or enable mTLS (server verify client).
	if !slices.Contains([]string{"", "true", "false", "skip-verify", "preferred"}, conf.MysqlConfig.TLSConfigKey) {
		panic(
			fmt.Sprintf(
				"tls mod not supported: %s, refer to https://github.com/go-sql-driver/mysql#tls",
				conf.MysqlConfig.TLSConfigKey,
			),
		)
	}

	gormDb, err := gormutil.Connect(conf.MysqlConfig)
	if err != nil {
		panic(err)
	}

	if err := gormDb.Use(otelgorm.NewPlugin(
		otelgorm.WithoutMetrics(),
		otelgorm.WithDBName(conf.MysqlConfig.Database),
	)); err != nil {
		panic(err)
	}

	if err := gormDb.Use(prometheus.New(prometheus.Config{
		DBName:          conf.MysqlConfig.Database,
		RefreshInterval: 15,
		StartServer:     false,
	})); err != nil {
		panic(err)
	}

	tilog.PlainInfo("Initialize global databases successfully")

	globalDB = gormDb
	return gormDb
}

func NewDBProvider(gormDB *gorm.DB) (db.Provider, db.TransProvider, db.Transactioner) {
	provider := db.NewProvider(gormDB)
	return provider, provider, provider
}
