package connection

import (
	config "common/configsYaml"
	"common/rabbitmq"
	"gorm.io/gorm"
	"goutil/logUtilPlus"
	"strconv"
	"time"
)

var (
	// 存放实体结构
	dbModelMap = make([]interface{}, 0)

	//当前管理数据库
	modelDB *gorm.DB
)

func init() {

	// 启动异步处理
	go ExecuteCreateChan()
	go ExecuteSaveChan()
	go ExecuteDeleteChan()
}

// RegisterDBModel 注册数据库模型到全局变量dbModelMap中。
// 这个函数接受一个interface{}类型的参数dbModel，表示数据库模型。
// 函数的目的是将传入的数据库模型添加到全局变量dbModelMap中，
// 以便在其他地方可以访问和使用这些数据库模型。
func RegisterDBModel(dbModel interface{}) {
	// 将dbModel的地址添加到dbModelMap中。
	// 这里使用地址是因为数据库模型可能比较大，通过引用存储可以提高效率。
	dbModelMap = append(dbModelMap, &dbModel)
}

// SetModelDB 设置modelDB 类型
func SetModelDB(db *gorm.DB) {
	modelDB = db
}

// BuildDB 用于遍历dbModelMap中的所有数据库模型，并检查每个模型对应的表是否存在于数据库中。
// 如果表不存在，则自动迁移（创建）该表。这样可以确保数据库模式与程序中的模型保持同步。
func BuildDB() {
	// 遍历dbModelMap中的每个元素
	for _, dbModel := range dbModelMap {

		// 检查数据库中是否存在与dbModel对应的表
		CheckTableExists(modelDB, dbModel)
	}
}

// CheckTableExists 检查表是否存在,不存在则添加
func CheckTableExists(db *gorm.DB, value interface{}) bool {

	// 检查数据库中是否存在与dbModel对应的表
	tableExists := db.Migrator().HasTable(value)
	if !tableExists {
		// 如果表不存在，则进行自动迁移
		err := db.AutoMigrate(value)
		if err != nil {
			logUtilPlus.ErrorLog("CheckTableExists is err: %v", err.Error())
			return false
		}
	}

	return true
}

// GetMonth 获取当前月份
func GetMonth() int32 {
	month, err := strconv.Atoi(time.Now().Format("200601"))
	if err != nil {
		logUtilPlus.ErrorLog("GetMonth is err: %v", err.Error())
		return 0
	}
	return int32(month)
}

// GetToMonthAdd 获取当前月份 加上指定个月
func GetToMonthAdd(monthCount int32) int32 {
	month, err := strconv.Atoi(time.Now().AddDate(0, int(monthCount), 0).Format("200601"))
	if err != nil {
		logUtilPlus.ErrorLog("GetToMonthAdd is err: %v", err.Error())
		return 0
	}
	return int32(month)
}

// Create 添加数据
// @param db 数据库连接
// @param value 值
// @param dbIndex mq队列索引
func Create(db *gorm.DB, value interface{}, dbIndex int32) *gorm.DB {

	result := &gorm.DB{Error: nil}

	//检查表是否存在
	CheckTableExists(db, value)

	//转换sql mq远程执行
	if config.GetSqlUseMQ() {
		sql := db.ToSQL(func(tx *gorm.DB) *gorm.DB {
			return tx.Model(value).Create(value)
		})

		//推送数据到mq
		rabbitmq.SendMqData(dbIndex, sql)

		//直接返回
		return result
	}

	result = db.Create(value)
	if result.Error != nil {
		logUtilPlus.ErrorLog("数据创建失败：", result.Error.Error())
	}

	return result
}

// Save 保存数据
func Save(db *gorm.DB, value interface{}, dbIndex int32) *gorm.DB {

	result := &gorm.DB{Error: nil}

	//转换sql mq远程执行
	if config.GetSqlUseMQ() {
		sql := db.ToSQL(func(tx *gorm.DB) *gorm.DB {
			return tx.Model(value).Save(value)
		})

		//推送数据到mq
		rabbitmq.SendMqData(dbIndex, sql)

		return result
	}

	result = db.Save(value)

	if result.Error != nil {
		logUtilPlus.ErrorLog("数据保存失败：", result.Error.Error())
	}

	return result
}

// DBData 添加数据通道
type DBData struct {
	DB    *gorm.DB
	Value any
}

var (

	// 添加数据通道
	createChan = make(chan DBData)

	// 保存数据通道
	saveChan = make(chan DBData)

	// 删除数据通道
	deleteChan = make(chan DBData)
)

// AsyncCreate 异步创建数据
func AsyncCreate(db *gorm.DB, value interface{}) {

	createChan <- DBData{
		DB:    db,
		Value: value,
	}
}

// ExecuteCreateChan 执行添加数据通道
func ExecuteCreateChan() {
	defer func() {
		if err := recover(); err != nil {
			logUtilPlus.ErrorLog("AsyncCreate is err: %v", err)

			//停止程序
			panic(err)
		}
	}()

	for {
		select {
		case createData := <-createChan:
			db := createData.DB
			value := createData.Value

			//检查表是否存在
			CheckTableExists(db, value)
			result := db.Create(value)
			if result.Error != nil {
				logUtilPlus.ErrorLog("AsyncCreate is err: %v", result.Error)
			}
		}
	}
}

// AsyncSave 异步保存数据
func AsyncSave(db *gorm.DB, value interface{}) {

	saveChan <- DBData{
		DB:    db,
		Value: value,
	}
}

// ExecuteSaveChan 执行保存数据通道
func ExecuteSaveChan() {

	defer func() {
		if err := recover(); err != nil {
			logUtilPlus.ErrorLog("AsyncSave is err: %v", err)
			panic(err)
		}
	}()
	for {
		select {
		case saveData := <-saveChan:
			db := saveData.DB
			value := saveData.Value

			result := db.Save(value)
			if result.Error != nil {
				logUtilPlus.ErrorLog("AsyncSave is err : %v", result.Error)
			}
		}
	}
}

// AsyncDelete 异步删除数据
func AsyncDelete(db *gorm.DB, value interface{}) {

	deleteChan <- DBData{
		DB:    db,
		Value: value,
	}
}

// ExecuteDeleteChan 执行删除数据通道
func ExecuteDeleteChan() {

	defer func() {
		if err := recover(); err != nil {
			logUtilPlus.ErrorLog("AsyncDelete is err: %v", err)
			panic(err)
		}
	}()
	for {
		select {
		case deleteData := <-deleteChan:
			db := deleteData.DB
			value := deleteData.Value

			result := db.Delete(value)
			if result.Error != nil {
				logUtilPlus.ErrorLog("AsyncDelete is err : %v", result.Error)
			}
		}
	}
}
