package gorm

import (
	"fmt"

	"github.com/tidbcloud/devops/pkg/infra/config"
	"github.com/tidbcloud/devops/pkg/infra/log"

	mysqld "github.com/go-sql-driver/mysql"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	gormlog "gorm.io/gorm/logger"
)

func GenerateDSN(conf config.DatabaseConfig) string {
	dbConf := mysqld.NewConfig()
	dbConf.Net = "tcp"
	dbConf.User = conf.User
	dbConf.Addr = fmt.Sprintf("%s:%d", conf.Host, conf.Port)
	dbConf.Passwd = conf.Password
	dbConf.DBName = conf.Database
	dbConf.ParseTime = true
	dbConf.Timeout = conf.DailTimeout
	dbConf.ReadTimeout = conf.ReadTimeout
	dbConf.WriteTimeout = conf.WriteTimeout
	dbConf.Params = map[string]string{"charset": "utf8mb4"}
	for k, v := range conf.Params {
		dbConf.Params[k] = v
	}
	dbConf.Collation = "utf8mb4_bin"
	dbConf.TLSConfig = conf.TLSConfigKey
	return dbConf.FormatDSN()
}

func Connect(conf config.DatabaseConfig, name string) (*gorm.DB, error) {
	logConf := gormlog.Config{
		SlowThreshold:             conf.LogSlowThreshold,
		LogLevel:                  gormlog.LogLevel(conf.LogLevel),
		IgnoreRecordNotFoundError: true,
	}
	dbConf := &gorm.Config{
		Logger: NewGormLogger(logConf, name, conf.TraceQuerySQL),
	}
	dsn := GenerateDSN(conf)

	db, err := gorm.Open(mysql.Open(dsn), dbConf)
	if err != nil {
		return nil, fmt.Errorf("open database %s:%d failed: %w", conf.Host, conf.Port, err)
	}

	sqlDB, err := db.DB()
	if err != nil {
		return nil, fmt.Errorf("get sql database failed: %w", err)
	}
	sqlDB.SetConnMaxLifetime(conf.ConnMaxLifetime)
	sqlDB.SetMaxIdleConns(conf.MaxIdleConns)
	sqlDB.SetMaxOpenConns(conf.MaxOpenConns)

	log.Logger.WithName(name).Info("connect to db successfully", "host", conf.Host, "port", conf.Port)
	return db, nil
}
