package db

import (
	"database/sql"
	"errors"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"log/slog"
	"os"
	"path/filepath"
	"slgserver/config"
	"time"
	"xorm.io/xorm"
	"xorm.io/xorm/log"
)

var MasterDB *xorm.Engine

var logFileHandle *os.File

var (
	ConnectDBErr = errors.New("connect db error")
	UseDBErr     = errors.New("use db error")
)

// TestDB 测试数据库
func TestDB() error {
	mysqlConfig, err := config.GetSection("mysql")
	if err != nil {
		slog.Error("get mysql config error", "error", err)
		panic(err)
	}

	tmpDns := fmt.Sprintf("%s:%s@tcp(%s:%s)/?charset=%s&parseTime=True&loc=Local",
		mysqlConfig["user"],
		mysqlConfig["password"],
		mysqlConfig["host"],
		mysqlConfig["port"],
		mysqlConfig["charset"])
	egnine, err := xorm.NewEngine("mysql", tmpDns)
	if err != nil {
		slog.Error("new engine error", "error", err)
		panic(err)
	}
	defer egnine.Close()

	// 测试数据库连接是否 OK
	if err = egnine.Ping(); err != nil {
		slog.Error("ping db error", "error", err)
		return ConnectDBErr
	}

	_, err = egnine.Exec("use " + mysqlConfig["dbname"])
	if err != nil {
		slog.Error("use db error", "error", err)
		// 使用参数化查询避免SQL注入风险
		createDBQuery := fmt.Sprintf("CREATE DATABASE `%s` DEFAULT CHARACTER SET %s", mysqlConfig["dbname"], mysqlConfig["charset"])
		_, err = egnine.Exec(createDBQuery)
		if err != nil {
			slog.Error("create database error", "error", err)

			return UseDBErr
		}

		slog.Info("create database successfully")
	}

	// 初始化 MasterDB
	return Init()
}

func Init() error {
	mysqlConfig, err := config.GetSection("mysql")
	if err != nil {
		slog.Error("get mysql config error", "error", err)
		return err
	}

	// 启动时就打开数据库连接
	if err = initEngine(mysqlConfig); err != nil {
		slog.Error("mysql is not open", "error", err)
		return err
	}

	return nil
}

func fillDns(mysqlConfig map[string]string) string {
	return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=True&loc=Local",
		mysqlConfig["user"],
		mysqlConfig["password"],
		mysqlConfig["host"],
		mysqlConfig["port"],
		mysqlConfig["dbname"],
		mysqlConfig["charset"])
}

func initEngine(mysqlConfig map[string]string) error {

	var err error
	dns := fillDns(mysqlConfig)

	MasterDB, err = xorm.NewEngine("mysql", dns)
	if err != nil {
		return err
	}

	// 数据库连接池配置，根据实际负载调整
	maxIdle := config.GetInt("mysql.max_idle", 10)   // 默认值从2提升到10
	maxConn := config.GetInt("mysql.max_conn", 100)  // 默认值从10提升到100

	MasterDB.SetMaxIdleConns(maxIdle)
	MasterDB.SetMaxOpenConns(maxConn)
	
	// 设置连接最大生存时间，避免长时间连接导致的问题
	MasterDB.SetConnMaxLifetime(time.Hour)

	showSQL := config.GetBool("xorm.show_sql", false)
	logLevel := config.GetInt("xorm.log_level", 1)
	logFile := config.GetPath("xorm.log_file", "")

	if logFile != "" {
		if logFileHandle != nil {
			logFileHandle.Close()
		}
		// 确保日志文件目录存在
		if err := os.MkdirAll(filepath.Dir(logFile), 0755); err != nil {
			return fmt.Errorf("failed to create log directory: %w", err)
		}
		f, err := os.OpenFile(logFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
		if err != nil {
			return err
		}
		logFileHandle = f
		MasterDB.SetLogger(log.NewSimpleLogger(f))
	}

	MasterDB.SetLogLevel(log.LogLevel(logLevel))
	MasterDB.ShowSQL(showSQL)

	return nil
}

func StdMasterDB() *sql.DB {
	return MasterDB.DB().DB
}

func Close() {
	if MasterDB != nil {
		MasterDB.Close()
	}
	if logFileHandle != nil {
		logFileHandle.Close()
	}
}
