package db

import (
	"fmt"
	golog "log"
	"os"
	"time"

	mysqlconfig "github.com/go-sql-driver/mysql"
	"github.com/pingcap/dbaas/billing2/config"
	"github.com/pingcap/errors"
	"github.com/pingcap/log"
	"github.com/spf13/viper"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

// globalDB represents the global database connection pool instance and all
// database operation should use db.Transaction interface to retrieve a
// transaction object.
var globalDB *gorm.DB

func getDSN(isSetupDB bool) string {
	user := viper.GetString(config.MySQLUser)
	password := viper.GetString(config.MySQLPassword)
	database := viper.GetString(config.Database)
	host := viper.GetString(config.MySQLHost)
	port := viper.GetInt(config.MYSQLPort)
	config := mysqlconfig.NewConfig()
	config.Net = "tcp"
	config.User = user
	config.Addr = fmt.Sprintf("%s:%d", host, port)
	config.Passwd = password
	if isSetupDB {
		config.DBName = ""
	} else {
		config.DBName = database
	}
	config.ParseTime = true
	config.Timeout = 30 * time.Second
	config.ReadTimeout = 30 * time.Second
	config.WriteTimeout = 30 * time.Second
	config.Params = map[string]string{"charset": "utf8mb4"}
	config.Collation = "utf8mb4_bin"
	return config.FormatDSN()
}

var newLogger = logger.New(
	golog.New(os.Stdout, "\r\n", golog.LstdFlags),
	logger.Config{
		SlowThreshold:             200 * time.Millisecond,
		LogLevel:                  logger.Warn,
		IgnoreRecordNotFoundError: true,
		Colorful:                  false,
	},
)

func GetSetupDB() (*gorm.DB, error) {
	dsn := getDSN(true)

	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		Logger: newLogger,
	})

	if err != nil {
		return nil, errors.Trace(err)
	}
	return db, nil
}

// Initialize initializes the global database connection pool and return error
// if some unexpected errors from the driver and gorm package raised.
func Initialize() (*gorm.DB, error) {
	dsn := getDSN(false)
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		Logger: newLogger,
	})
	if err != nil {
		return nil, errors.Trace(err)
	}

	globalDB = db

	log.Info("Initialize database successfully")

	return db, nil
}

func GetDB() *gorm.DB {
	return globalDB
}
