package db

import (
	//"database/sql"
	"fmt"
	"reflect"
	"server/GoUtil"
	"server/conf"
	"server/pkg/github.com/name5566/leaf/log"
	"strings"

	// "server/game"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
)

type user struct {
	Id       int    `db:"user_id"`
	Sex      int    `db:"sex"`
	UserName string `db:"username"`
	Email    string `db:"email"`
}

var SqlDb *sqlx.DB

func InitDB() {
	//"用户名:密码@[连接方式](主机名:端口号)/数据库名"
	MysqlPwd, _ := GoUtil.Decrypt(conf.Server.MySqlPwd)
	connect := fmt.Sprintf("%s:%s@(%s:%s)/%s", conf.Server.MySqlUsr, MysqlPwd, conf.Server.MySqlAddr, conf.Server.MySqlPort, conf.Server.DbName)
	SqlDb = sqlx.MustConnect("mysql", connect) // 设置连接数据库的参数
	SqlDb.SetMaxOpenConns(20)                  // 设置最大打开的连接数
	log.Debug("connect mysql success")
}

func SeriesTransaction(sqlstrs []string, params [][]any) (err error) {
	tx, err := SqlDb.Begin()
	if err != nil {
		log.Debug("Transaction failed, err:%v\n", err)
		return err
	}

	defer func() {
		if err != nil {
			log.Debug("Transaction failed, err:%v\n", err)
			_ = tx.Rollback()
		} else {
			err = tx.Commit()
			return
		}
	}()

	for i := 0; i < len(sqlstrs); i++ {
		_, err := tx.Exec(sqlstrs[i], params[i]...)
		if err != nil {
			log.Debug("Transaction failed, err:%v\n", err)
			return err
		}

	}

	return
}

// 更新数据
func FormatUpdateOneAttrRow(u interface{}, tableName string, UpdateAttr string, Exclude string) (err error) {
	t := reflect.TypeOf(u)
	len1 := t.Elem().NumField()
	Fields := make([]string, len1)
	Values := make([]interface{}, len1)
	pp := reflect.ValueOf(u)
	origin := "UPDATE " + tableName + " SET "
	index := 0
	var keyValue interface{}
	for i := 0; i < len1; i++ {
		field := t.Elem().Field(i)
		if field.Tag.Get("db") != Exclude {
			if field.Tag.Get("db") == UpdateAttr {
				Fields[index] = field.Tag.Get("db") + " = ?"

				ufield := pp.Elem().FieldByName(field.Name)
				k := ufield.Kind()
				if k == reflect.String {
					Values[index] = ufield.String()
				}
				if k == reflect.Int32 {
					Values[index] = ufield.Int()
				}
				index++
			}

		} else {

			ufield := pp.Elem().FieldByName(field.Name)
			k := ufield.Kind()
			if k == reflect.String {
				keyValue = ufield.String()
			}
			if k == reflect.Int32 {
				keyValue = ufield.Int()
			}
		}
	}
	Values[index] = keyValue
	// Values = append(Values, keyValue)
	origin += strings.Join(Fields, ",")
	strLen := len(origin)
	origin = origin[:strLen-1]
	origin = origin + " WHERE " + Exclude + " = ?"
	sqlStr := origin
	_, err = SqlDb.Exec(sqlStr, Values...)
	if err != nil {
		log.Debug("table: %s, sql :%s, exec failed, err:%v\n", tableName, sqlStr, err)
		return
	}

	return
}

// "UPDATE user SET age = ?, degree = ? WHERE id = ?"
func FormatAllMemUpdateDb(u interface{}, tableName string, Exclude string) (err error) {
	t := reflect.TypeOf(u)
	len1 := t.Elem().NumField()
	Fields := make([]string, len1)
	Values := make([]interface{}, len1)
	pp := reflect.ValueOf(u)
	origin := "UPDATE " + tableName + " SET "
	index := 0
	var keyValue interface{}
	for i := 0; i < len1; i++ {
		field := t.Elem().Field(i)
		if field.Tag.Get("db") != Exclude {
			Fields[index] = "`" + field.Tag.Get("db") + "` = ?"

			ufield := pp.Elem().FieldByName(field.Name)
			k := ufield.Kind()
			if k == reflect.String {
				Values[index] = ufield.String()
			}
			if k == reflect.Int32 || k == reflect.Int || k == reflect.Int64 {
				Values[index] = ufield.Int()
			}
			index++
		} else {
			ufield := pp.Elem().FieldByName(field.Name)
			k := ufield.Kind()
			if k == reflect.String {
				keyValue = ufield.String()
			}
			if k == reflect.Int32 || k == reflect.Int || k == reflect.Int64 {
				keyValue = ufield.Int()
			}
		}
	}
	Values[index] = keyValue
	// Values = append(Values, keyValue)
	origin += strings.Join(Fields, ",")
	strLen := len(origin)
	origin = origin[:strLen-1]
	origin = origin + " WHERE `" + Exclude + "` = ?"
	sqlStr := origin

	_, err = SqlDb.Exec(sqlStr, Values...)
	if err != nil {
		log.Debug("table: %s, sql :%s, exec failed, err:%v\n", tableName, sqlStr, err)
		return
	}
	return
}
func FormatAllMemInsertDb(u interface{}, tableName string) (insertID int64, err error) {
	t := reflect.TypeOf(u)
	len := t.Elem().NumField()
	Fields := make([]string, len)
	Fields1 := make([]string, len)
	FieldNames := make([]string, len)
	Values := make([]interface{}, len)
	pp := reflect.ValueOf(u)
	origin := "INSERT INTO " + tableName + "("
	for i := 0; i < len; i++ {
		field := t.Elem().Field(i)
		Fields[i] = field.Tag.Get("db")
		Fields1[i] = "?"
		FieldNames[i] = field.Name
		ufield := pp.Elem().FieldByName(field.Name)
		k := ufield.Kind()
		if k == reflect.String {
			Values[i] = ufield.String()
		}
		if k == reflect.Int32 {
			Values[i] = ufield.Int()
		}
		if k == reflect.Int64 {
			Values[i] = ufield.Int()
		}
	}
	for i := range Fields {
		Fields[i] = "`" + Fields[i] + "`"
	}
	origin += strings.Join(Fields, ",")
	origin += ") VALUES("
	origin += strings.Join(Fields1, ",")
	origin += ")"
	sqlStr := origin
	result, err := SqlDb.Exec(sqlStr, Values...)
	if err != nil {
		log.Debug("table: %s, sql :%s, exec failed, err:%v\n", tableName, sqlStr, err)
		return
	}
	insertID, err = result.LastInsertId()
	if err != nil {
		log.Debug("table: %s, sql :%s, exec failed, err:%v\n", tableName, sqlStr, err)
		return
	}
	return
}

func GetPlayerBaseInfoFromDbByName(name string) *ResPlayerBaseInfo {
	sqlStr := "SELECT * FROM t_player_baseinfo WHERE user_name = ?"
	var res ResPlayerBaseInfo
	if err := SqlDb.Get(&res, sqlStr, name); err != nil {
		log.Debug("table: %s, sql :%s, exec failed, err:%v\n", "PlayerBaseInfo", sqlStr, err)
		return nil
	}
	return &res
}

func GetPlayerBaseInfoFromDbById(id int32) *ResPlayerBaseInfo {
	sqlStr := "SELECT * FROM t_player_baseinfo WHERE dwUin = ?"
	var res ResPlayerBaseInfo
	if err := SqlDb.Get(&res, sqlStr, id); err != nil {
		log.Debug("table: %s, sql :%s, exec failed, err:%v\n", "PlayerBaseInfo", sqlStr, err)
		return nil
	}
	return &res
}

func GetAccountInfoFromDb(name string) *Db_Account {
	sqlStr := "SELECT * FROM t_account WHERE user_name = ?"
	var res Db_Account
	if err := SqlDb.Get(&res, sqlStr, name); err != nil {
		log.Debug("table: %s, sql :%s, exec failed, err:%v\n", "account", sqlStr, err)
		return nil
	}
	return &res
}

func FormatAllMemLoadDb(u interface{}, tableName string, Exclude string) (err error) {
	t := reflect.TypeOf(u)
	len := t.Elem().NumField()
	Fields := make([]string, len)
	Values := make([]interface{}, len)
	pp := reflect.ValueOf(u)
	origin := "SELECT * FROM " + tableName + " WHERE "
	index := 0
	var keyValue interface{}
	for i := 0; i < len; i++ {
		field := t.Elem().Field(i)
		if field.Tag.Get("db") != Exclude {
			Fields[index] = field.Tag.Get("db") + " = ?"

			ufield := pp.Elem().FieldByName(field.Name)
			k := ufield.Kind()
			if k == reflect.String {
				Values[index] = ufield.String()
			}
			if k == reflect.Int32 || k == reflect.Int || k == reflect.Int64 {
				Values[index] = ufield.Int()
			}
			index++
		} else {

			ufield := pp.Elem().FieldByName(field.Name)
			k := ufield.Kind()
			if k == reflect.String {
				keyValue = ufield.String()
			}
			if k == reflect.Int32 {
				keyValue = ufield.Int()
			}
		}
	}
	Values[index] = keyValue
	// Values = append(Values, keyValue)
	origin += strings.Join(Fields, " AND ")
	sqlStr := origin
	if err := SqlDb.Get(u, sqlStr, Values...); err != nil {
		log.Debug("table: %s, sql :%s, exec failed, err:%v\n", tableName, sqlStr, err)
		return err
	}
	return
}

func GetServerData(d interface{}, Key string) (err error) {
	sql := "select * from t_server_mod where `key` = ?"
	err = SqlDb.Get(d, sql, Key)
	return
}

func SaveServerData(data *SqlServerModStruct) error {
	sql := "update t_server_mod set `mData` = ? , `updateTime` = ? where `key` = ?"
	_, err := SqlDb.Exec(sql, data.ModData, data.UpdataTime, data.Key)
	return err
}

func InsertServerData(data *SqlServerModStruct) error {
	sql := "insert into t_server_mod (`mData` , `updateTime` ,`key`) Values (?,?,?)"
	_, err := SqlDb.Exec(sql, data.ModData, data.UpdataTime, data.Key)
	return err
}

func SavePlayerModData(data *SqlModStruct) error {
	sql := "INSERT INTO `t_player_mod` (`mData` , `updateTime` ,`dwUin`) Values (?,?,?) ON DUPLICATE KEY UPDATE `mData` = ? , `updateTime` = ? "
	_, err := SqlDb.Exec(sql, data.ModData, data.UpdataTime, data.DwUin, data.ModData, data.UpdataTime)
	return err
}

func InsertPlayerModData(data *SqlModStruct) error {
	sql := "insert into t_player_mod (`mData` , `updateTime` ,`dwUin`) Values (?,?,?)"
	_, err := SqlDb.Exec(sql, data.ModData, data.UpdataTime, data.DwUin)
	return err
}

func SavePlayerClientData(data *SqlModStruct) error {
	sql := "INSERT INTO `t_player_client_data` (`mData` , `updateTime` ,`dwUin`) Values (?,?,?) ON DUPLICATE KEY UPDATE `mData` = ? , `updateTime` = ? "
	_, err := SqlDb.Exec(sql, data.ModData, data.UpdataTime, data.DwUin, data.ModData, data.UpdataTime)
	return err
}

func GetPlayerClientData(d interface{}, Key string) (err error) {
	sql := "select * from t_server_mod where `dwUin` = ?"
	err = SqlDb.Get(d, sql, Key)
	return
}

func InsertData(u interface{}, tableName string) (insertID int64, err error) {
	t := reflect.TypeOf(u)
	len := t.Elem().NumField()
	Fields := make([]string, 0)
	Fields1 := make([]string, 0)
	Values := make([]interface{}, 0)
	pp := reflect.ValueOf(u)
	origin := "INSERT INTO " + tableName + "("
	for i := 0; i < len; i++ {
		field := t.Elem().Field(i)
		if field.Tag.Get("db") == "id" {
			continue
		}

		ufield := pp.Elem().FieldByName(field.Name)
		k := ufield.Kind()
		if k == reflect.String && ufield.String() == "" {
			continue
		}
		if (k == reflect.Int32 || k == reflect.Int || k == reflect.Int64) && ufield.Int() == 0 {
			continue
		}

		if k == reflect.String {
			Values = append(Values, ufield.String())
		}
		if k == reflect.Int32 || k == reflect.Int || k == reflect.Int64 {
			Values = append(Values, ufield.Int())
		}
		Fields = append(Fields, field.Tag.Get("db"))
		Fields1 = append(Fields1, "?")
	}
	for i := range Fields {
		Fields[i] = "`" + Fields[i] + "`"
	}
	origin += strings.Join(Fields, ",")
	origin += ") VALUES("
	origin += strings.Join(Fields1, ",")
	origin += ")"
	sqlStr := origin
	result, err := SqlDb.Exec(sqlStr, Values...)
	if err != nil {
		log.Debug("InsertData exec failed, sql : %s ;err:%v\n", sqlStr, err)
		return
	}
	insertID, err = result.LastInsertId()
	if err != nil {
		log.Debug("InsertData exec failed, err:%v\n", err)
		return
	}
	return
}

func UpdateData(u interface{}, tableName string, Exclude string) (err error) {
	t := reflect.TypeOf(u)
	len1 := t.Elem().NumField()
	Fields := make([]string, 0)
	Values := make([]interface{}, 0)
	pp := reflect.ValueOf(u)
	origin := "UPDATE " + tableName + " SET "
	var ExcludeValue interface{}
	for i := 0; i < len1; i++ {
		field := t.Elem().Field(i)
		ufield := pp.Elem().FieldByName(field.Name)
		k := ufield.Kind()
		if field.Tag.Get("db") != Exclude && field.Tag.Get("db") != "id" {

			if k == reflect.String {
				Values = append(Values, ufield.String())
			}
			if k == reflect.Int32 || k == reflect.Int || k == reflect.Int64 {
				Values = append(Values, ufield.Int())
			}
			Fields = append(Fields, "`"+field.Tag.Get("db")+"` = ?")
		}
		if field.Tag.Get("db") == Exclude {
			if k == reflect.String {
				ExcludeValue = ufield.String()
			}
			if k == reflect.Int32 || k == reflect.Int || k == reflect.Int64 {
				ExcludeValue = append(Values, ufield.Int())
			}
		}
	}
	Values = append(Values, ExcludeValue)
	origin += strings.Join(Fields, ",")
	origin = origin + " WHERE `" + Exclude + "` = ?"
	sqlStr := origin

	_, err = SqlDb.Exec(sqlStr, Values...)
	if err != nil {
		log.Debug("update failed, sql %s err:%v\n", sqlStr, err)
		return
	}
	return
}

func GetServerMailData(data *[]*SqlServerMailStruct) error {
	sql := "select * from system_mail_info"
	err := SqlDb.Select(data, sql)
	return err
}

func CreateOrderSn(Uid, ChargeId int, OrderSn, Platform, Channel string, Price float64, Currency string) error {
	sql := "insert into t_player_charge (`Uid`,`OrderId`, `ProductId`, `Price`,`Currency`, `CreateTime`, `PayPlatform`, `PayChannel`) Values (?,?,?,?,?,?,?,?)"
	Now := GoUtil.Now()
	_, err := SqlDb.Exec(sql, Uid, OrderSn, ChargeId, Price, Currency, Now, Platform, Channel)
	return err
}

func GetPlayerChargeData(OrderSn string) (*SqlChargeOrderStruct, error) {
	sql := "select * from t_player_charge where OrderId = ?"
	data := &SqlChargeOrderStruct{}
	err := SqlDb.Get(data, sql, OrderSn)
	return data, err
}

func GetPlayerPayChannelOrderId(OrderSn string) (*SqlChargeOrderStruct, error) {
	sql := "select * from t_player_charge where PayChannelOrderId = ?"
	data := &SqlChargeOrderStruct{}
	err := SqlDb.Get(data, sql, OrderSn)
	return data, err
}

func UpdatePlayerChargeData(data *SqlChargeOrderStruct) error {
	sql := "update t_player_charge set PayTime = ?, PayStatus = ?, PayChannelOrderId = ? where OrderId = ?"
	_, err := SqlDb.Exec(sql, data.PayTime, data.PayStatus, data.PayChannelOrderId, data.OrderId)
	return err
}

func SearchPlayer(key string) ([]*ResPlayerBaseInfo, error) {
	sql := "select * from t_player_baseinfo where nick_name like ? limit 10"
	data := &[]*ResPlayerBaseInfo{}
	err := SqlDb.Select(data, sql, "%"+key+"%")
	return *data, err
}
