package test

import (
	"context"
	"encoding/json"
	"fmt"
	"math/rand"
	"os"

	"github.com/tidbcloud/account/internel/svc/migrate"

	dbinit "github.com/tidbcloud/account/commons/database"

	"github.com/creasty/defaults"
	"github.com/stretchr/testify/suite"
	"github.com/tidbcloud/account/commons/config"
	"github.com/tidbcloud/account/pkg/gormutil"
	panicIf "github.com/tidbcloud/pkgv2/panicif"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"gorm.io/gorm"
)

var gormdb *gorm.DB = nil

func setDefaultTestConfig() {
	config.Global().MysqlConfig = config.MysqlConfig{
		Host: "127.0.0.1",
		User: "root",
		Port: 3306,
	}
}

func setupTestConfigFromEnv() {
	setDefaultTestConfig()
	result := map[string]interface{}{}
	mysqlTestConfig, ok := os.LookupEnv("MYSQL_TEST_CONFIG")
	if !ok {
		return
	}
	panicIf.Error(json.Unmarshal([]byte(mysqlTestConfig), &result))
	config.Global().MysqlConfig.Host = result["host"].(string)
	config.Global().MysqlConfig.Port = uint16(result["port"].(float64))
	config.Global().MysqlConfig.User = result["user"].(string)
	config.Global().MysqlConfig.Password = result["password"].(string)
}

func getSetupDB(cfg config.MysqlConfig) (*gorm.DB, error) {
	connCfg := gormutil.Config{
		User:              cfg.User,
		Host:              cfg.Host,
		Password:          cfg.Password,
		Port:              cfg.Port,
		EnableDetailedLog: config.Global().ServerConfig.EnableDBQueryLog,
		LogLevel:          config.Global().ServerConfig.LogLevel,
	}
	return gormutil.Connect(connCfg)
}

func setupDB() {
	database := fmt.Sprintf("unittest_dbaas_%v", rand.Int())
	config.Global().MysqlConfig.Database = database
	gormdb, err := getSetupDB(config.Global().MysqlConfig)
	panicIf.Error(err)
	panicIf.Error(gormdb.Exec(fmt.Sprintf("drop database if exists %v", database)).Error)
	panicIf.Error(gormdb.Exec(fmt.Sprintf("create database %v CHARACTER SET utf8mb4 COLLATE utf8mb4_bin", database)).Error)

	dbinit.ResetInitialize()

	db, err := dbinit.Initialize(context.Background(), config.Global().MysqlConfig)
	panicIf.Error(err)
	ctx := context.Background()
	tilog.Info(ctx, "before migrate")
	panicIf.Error(migrate.RunCentralMigrate(db))
	tilog.Info(ctx, "end migrate")
}

func tearDownDB() {
	if gormdb != nil {
		panicIf.Error(gormdb.Exec(fmt.Sprintf("drop database if exists %v", config.Global().MysqlConfig.Database)).Error)
	}
}

type CentralTestSuite struct {
	suite.Suite
}

func (*CentralTestSuite) SetupTest() {
	Setup()
}

func (*CentralTestSuite) TearDownTest() {
	Shutdown()
}

func setupConfig() {
	panicIf.Error(defaults.Set(config.Global()))
}

func Setup() {
	setupConfig()
	setupTestConfigFromEnv()
	setupDB()
}

func Shutdown() {
	tearDownDB()
}
