package utils

import (
	"errors"
	"fmt"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
	"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log"
	"reflect"
)

// 更新指定表的几个列
func UpdateTableByMap(tabeleStruct interface{}, changeMap map[string]interface{}) error {
	if reflect.TypeOf(tabeleStruct).Kind() != reflect.Ptr {
		err := errors.New("UpdateTableByMap: tableStruct must ptr")
		beego.Error(err)
		return err
	}
	if len(changeMap) < 1 {
		beego.Info("changeMap is nil")
		return nil
	}
	o := orm.NewOrm()
	changeColumn := make([]string, 0, len(changeMap))
	for i, v := range changeMap {
		changeColumn = append(changeColumn, i)
		if err := SetStructValueByType(tabeleStruct, i, v); err != nil {
			beego.Error(err, i, v)
			return err
		}
	}
	num, err := o.Update(tabeleStruct, changeColumn...)
	if err != nil {
		beego.Error(err)
		return err
	}
	log.Info(fmt.Sprintf("UpdateTableByMap: table:%s effect records:%d column:%v", GetTableName(tabeleStruct), num, changeColumn))
	return nil
}

// 通过反射调用结构对应的TableName函数,达到返回表名的目的
func GetTableName(tableStruct interface{}) string {
	m := reflect.ValueOf(tableStruct).MethodByName("TableName")
	if m.IsValid() && m.Kind() == reflect.Func {
		re := m.Call(nil)
		for _, v := range re {
			if v.IsValid() {
				return v.String()
			}
		}
	}
	return "unknown"
}

// 通用事物提交sql结构体
type SqlData struct {
	Sql   string
	Param []interface{}
}

func ExecuteSqlByRoll(isCheck bool, sqlSlice ...*SqlData) bool {
	o := orm.NewOrm()
	var someError bool = false
	o.Begin()
	for i := range sqlSlice {
		if sqlSlice[i].Sql == "" {
			continue
		}
		log.Info("execute sql:", sqlSlice[i])
		if ret, err := o.Raw(sqlSlice[i].Sql, sqlSlice[i].Param...).Exec(); err != nil {
			log.Error(err)
			someError = true
		} else {
			num, _ := ret.RowsAffected()
			log.Debug("num:", num)
			if isCheck && num < 1 {
				someError = true
			}
		}
	}
	if someError {
		log.Error("出错,回滚事物")
		o.Rollback()
		return false
	} else {
		log.Info("成功,提交事物")
		o.Commit()
		return true
	}
	return true
}