package services

import (
	// "context"
	"fmt"
	"net/url"
	"sync"
	"time"

	"github.com/jmoiron/sqlx"

	_ "github.com/go-sql-driver/mysql" // MySQL驱动（匿名导入）
)

// Config 数据库连接配置
type Config struct {
	User            string        // 用户名
	Password        string        // 密码
	Host            string        // 主机地址（如localhost）
	Port            int           // 端口（默认3306）
	DBName          string        // 数据库名
	Charset         string        // 字符集（默认utf8mb4）
	ParseTime       bool          // 是否解析时间（必须为true，否则time.Time无法解析）
	Loc             string        // 时区（默认Local或Asia/Shanghai）
	MaxOpenConns    int           // 最大打开连接数（默认100）
	MaxIdleConns    int           // 最大空闲连接数（默认20）
	ConnMaxLifetime time.Duration // 连接最大存活时间（默认1小时）
	ConnMaxIdleTime time.Duration // 连接最大空闲时间（默认30分钟）
}

// DefaultConfig 返回默认配置（可直接修改字段覆盖）
func DefaultConfig(user string, password string, host string, port int, dbname string) *Config {

	escapedPassword := url.QueryEscape(password)
	return &Config{
		User:            user,
		Password:        escapedPassword, // 替换为你的MySQL密码
		Host:            host,
		DBName:          dbname,
		Port:            port,
		Charset:         "utf8mb4",
		ParseTime:       true,
		Loc:             "Local",
		MaxOpenConns:    20,
		MaxIdleConns:    5,
		ConnMaxLifetime: 1 * time.Hour,
		ConnMaxIdleTime: 30 * time.Minute,
	}
}

// DSN 生成MySQL连接字符串（Data Source Name）
func (c *Config) DSN() string {
	return fmt.Sprintf(
		"%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=%t&loc=%s",
		c.User,
		c.Password,
		c.Host,
		c.Port,
		c.DBName,
		c.Charset,
		c.ParseTime,
		c.Loc,
	)
}

// NewPool 初始化MySQL连接池
// 返回*sql.DB（Go内置连接池），使用后需调用Close()释放
func NewPool(config *Config) *sqlx.DB {

	// 打开数据库连接（不会立即建立连接，只是初始化连接池）
	db, err := sqlx.Open("mysql", config.DSN())
	if err != nil {
		build_time_str := time.Now().Format(time.DateTime)
		fmt.Printf("%s open db failed:======> %v\n", build_time_str, err)
		return nil
	}

	// 设置连接池参数
	db.SetMaxOpenConns(config.MaxOpenConns)       // 控制并发连接数
	db.SetMaxIdleConns(config.MaxIdleConns)       // 保持空闲连接，减少创建开销
	db.SetConnMaxLifetime(config.ConnMaxLifetime) // 避免连接被MySQL主动断开
	db.SetConnMaxIdleTime(config.ConnMaxIdleTime) // 清理长时间空闲的连接

	// 测试连接有效性
	if err := db.Ping(); err != nil {
		db.Close() // 测试失败时关闭连接池
		build_time_str := time.Now().Format(time.DateTime)
		fmt.Printf("%s ping db failed:======> %v\n", build_time_str, err)
		return nil
	}
	build_time := time.Now()
	build_time_str := build_time.Format(time.DateTime)
	fmt.Printf("%s mysql数据库连接池初始化成功\n", build_time_str)
	warmUpConnectionPoolConcurrently(db, 5)
	return db
}

func warmUpConnectionPoolConcurrently(db *sqlx.DB, warmUpCount int) error {
	var wg sync.WaitGroup
	errors := make(chan error, warmUpCount)

	for i := 0; i < warmUpCount; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()

			var dummy int
			err := db.QueryRow("SELECT 1").Scan(&dummy)
			if err != nil {
				errors <- fmt.Errorf("连接预热失败: %v", err)
			}
		}()
	}

	wg.Wait()
	close(errors)

	// 检查是否有错误
	for err := range errors {
		return err
	}
	build_time := time.Now()
	build_time_str := build_time.Format(time.DateTime)
	fmt.Printf("%s 并发预热 %d 个连接成功\n", build_time_str, warmUpCount)
	return nil
}
