package mysql

import (
	"common/config"
	pointQuery "common/db/mysql/point/query"
	"common/log"
	"database/sql"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"time"
)

type DBName string

const (
	DBNamePoint DBName = "point"
)

var dbs = make(map[DBName]*sql.DB)
var queryS = make(map[DBName]interface{})

func Init(cfg map[string]*config.MySQLConfig) error {
	for name, oneConfig := range cfg {
		switch DBName(name) {
		case DBNamePoint:
			if db, err := initOneDB(oneConfig); err != nil {
				return err
			} else {
				dbs[DBNamePoint], _ = db.DB()
				queryS[DBNamePoint] = pointQuery.Use(db)
			}
		}
	}
	return nil
}

func initOneDB(cfg *config.MySQLConfig) (*gorm.DB, error) {
	db, err := gorm.Open(
		mysql.Open(cfg.Dsn),
		&gorm.Config{
			TranslateError: true,
			Logger:         logger.Default.LogMode(parseLogLevel(cfg.LogLevel)),
		},
	)
	if err != nil {
		return nil, err
	}

	sqlDB, err := db.DB()
	if err != nil {
		return nil, err
	}
	sqlDB.SetMaxOpenConns(int(cfg.MaxOpenConn))
	sqlDB.SetMaxIdleConns(int(cfg.MaxIdleConn))
	sqlDB.SetConnMaxLifetime(time.Duration(cfg.ConnMaxLifetimeSec) * time.Second)
	sqlDB.SetConnMaxIdleTime(time.Duration(cfg.ConnMaxIdleTimeSec) * time.Second)

	return db, nil
}

func parseLogLevel(logLevel string) logger.LogLevel {
	switch logLevel {
	case "silent":
		return logger.Silent
	case "error":
		return logger.Error
	case "warn":
		return logger.Warn
	case "info":
		return logger.Info
	}
	return logger.Info
}

func GetPointDB() *pointQuery.Query {
	return getQuery[*pointQuery.Query](DBNamePoint)
}

func getQuery[T any](dbName DBName) (result T) {
	if q, ok := queryS[dbName]; ok {
		result, _ = q.(T)
	}
	return
}

func Close() error {
	if dbs == nil {
		return nil
	}
	for name, db := range dbs {
		if err := db.Close(); err != nil {
			log.Errorf("close db %s error: %v", name, err)
		}
	}
	return nil
}
