package excute

import (
	"cron_admin/app/utils"
	"encoding/json"
	"fmt"
	"gorm.io/gorm"
	"reflect"
	"strings"
	"time"
)

type ExecuteDb struct {
	Db     *gorm.DB
	DbName string
}

func NewExecuteDb(source string, dbName string) (*ExecuteDb, error) {
	db, err := ExecuteDbConn(source)
	if err != nil {
		return nil, fmt.Errorf("%s链接失败:%v", dbName, err)
	}
	return &ExecuteDb{Db: db, DbName: dbName}, nil
}

func (db *ExecuteDb) ExecuteRead(execute string) (result []map[string]interface{}, err error) {
	rows, err := db.Db.Raw(execute).Rows()
	if err != nil {
		return nil, fmt.Errorf("数据执行失败:%v", err.Error())
	}
	defer rows.Close()
	for rows.Next() {
		err = db.Db.ScanRows(rows, &result)
		if err != nil {
			return nil, fmt.Errorf("数据映射失败:%v", err)
		}
	}

	return result, nil
}

func (db *ExecuteDb) ExecuteWriteV2(readData []map[string]interface{}, execute string) (dbString string, err error) {
	var (
		dbExecuteSql []string
	)
	for _, v := range readData {
		dbExecuteSql = append(dbExecuteSql, db.replaceExecuteString(execute, v))
	}
	dbString = strings.Join(dbExecuteSql, ";")
	for _, v := range dbExecuteSql {
		d := db.Db.Exec(v)
		if d.Error != nil {
			return dbString, d.Error
		}
	}
	return dbString, nil
}

func (db *ExecuteDb) replaceExecuteString(execute string, rowData map[string]interface{}) string {
	executeString := execute
	for key, value := range rowData {
		formatValue := FormatValueData(value)
		key := fmt.Sprintf("${%s}", key)
		executeString = strings.Replace(executeString, key, fmt.Sprintf("%v", formatValue), -1)
	}
	return executeString
}

func FormatValueData(v interface{}) interface{} {
	var format interface{}
	switch v.(type) {
	case nil:
		format = "NULL"
	case time.Time:
		format = fmt.Sprintf("'%v'", v.(time.Time).Format("2006-01-02 15:04:05"))

	case []uint8:
		format = fmt.Sprintf("'%v'", string(v.([]uint8)))
	case string:
		format = fmt.Sprintf("'%v'", v)
	default:
		format = v
	}
	return format
}

func FilterReadData(data *[]map[string]interface{}, matchJson string) (filteredData []map[string]interface{}, err error) {
	if matchJson == "" {
		return *data, nil
	}
	for _, v := range *data {
		match, err := MatchJSON(v, &matchJson)
		if err != nil {
			return nil, err
		}
		if match {
			filteredData = append(filteredData, v)
		}
	}
	return filteredData, nil
}

func MatchJSON(mapData map[string]interface{}, jsonString *string) (bool, error) {
	// 解析JSON字符串
	var jsonData []Match
	err := json.Unmarshal([]byte(*jsonString), &jsonData)
	if err != nil {
		return false, fmt.Errorf("解析Match_Json失败:%v", err)
	}
	for _, v := range jsonData {
		// 判断key值
		mapData, err := judgeData(&v, mapData)
		if err != nil {
			return false, err
		}
		switch v.Op {
		case "=":
			if mapData[v.Key] != v.Val {
				return false, nil
			}
		case "!=":
			if mapData[v.Key] == v.Val {
				return false, nil
			}
		case "<":
			if mapData[v.Key].(int) >= v.Val.(int) {
				return false, nil
			}
		case "<=":
			if mapData[v.Key].(int) > v.Val.(int) {
				return false, nil
			}
		case ">":
			if mapData[v.Key].(int) <= v.Val.(int) {
				return false, nil
			}
		case ">=":
			if mapData[v.Key].(int) < v.Val.(int) {
				return false, nil
			}
		case "regex":
			if !utils.Regexp(mapData[v.Key].(string), v.Val.(string)) {
				return false, nil
			}
		default:
			return false, fmt.Errorf("未知的比较类型:%v", v.Op)
		}

	}

	return true, nil
}

func judgeData(v *Match, mapData map[string]interface{}) (map[string]interface{}, error) {
	if v.Key == "" {
		return nil, fmt.Errorf("Match_Json的key值未映射")
	}
	if v.Op == "" {
		return nil, fmt.Errorf("Match_Json的判断方式没找到")
	}

	if _, ok := mapData[v.Key]; !ok {
		return nil, fmt.Errorf("Match_Json的key值没找到:%s", v.Key)
	}

	// 判断类型
	valueKind := reflect.TypeOf(mapData[v.Key]).Kind()
	valKind := reflect.TypeOf(v.Val).Kind()
	if valKind == reflect.Float64 {
		v.Val = int(v.Val.(float64))
		valKind = reflect.TypeOf(v.Val).Kind()
	}
	if valueKind == reflect.Int64 {
		mapData[v.Key] = int(mapData[v.Key].(int64))
		valueKind = reflect.TypeOf(mapData[v.Key]).Kind()
	}

	if valueKind != reflect.String && valueKind != reflect.Int {
		return nil, fmt.Errorf("未知的val值类型:%s", v.Key)
	}

	if v.Op != "regex" && (valueKind != valKind) {
		return nil, fmt.Errorf("非正则模式Match_Json的val值类型不匹配:%s", v.Key)
	}

	if v.Op == "regex" && (valKind != reflect.String || valueKind != reflect.String) {
		return nil, fmt.Errorf("正则模式Match_Json的val值类型不匹配:%s", v.Key)
	}

	if utils.ContainsStr([]string{">", "<", ">=", "<="}, v.Op) && (valueKind == reflect.String || valKind == reflect.String) {
		return nil, fmt.Errorf("字符串类型val无法进行比较:%s", v.Key)
	}

	return mapData, nil
}