package mysql

import (
	"context"
	"fmt"
	"log"
	"os"
	"slices"
	"strings"
	"time"

	"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/gorm/logger"
	"gorm.io/plugin/prometheus"
)

func NewDB(conf *gormutil.Config) *gorm.DB {
	// 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.TLSConfigKey) {
		panic(fmt.Sprintf("tls mod not supported: %s, refer to https://github.com/go-sql-driver/mysql#tls", conf.TLSConfigKey))
	}

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

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

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

	replaceGormUtilLogger(gormDb, conf.LogLevel)

	tilog.Info(context.Background(), "initialize csng databases successfully")

	return gormDb
}

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

// Fxxk pkgv2 gormutil log.
func replaceGormUtilLogger(gdb *gorm.DB, level string) {
	var logLevel logger.LogLevel
	switch strings.ToLower(level) {
	case "fatal":
		logLevel = logger.Silent
	case "error":
		logLevel = logger.Error
	case "warn":
		logLevel = logger.Warn
	case "info":
		logLevel = logger.Info
	default:
		logLevel = logger.Warn
	}
	gdb.Logger = logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Config{
		SlowThreshold:             300 * time.Millisecond,
		LogLevel:                  logLevel,
		IgnoreRecordNotFoundError: true,
		Colorful:                  true,
	})
}
