package dao

import (
	"fmt"
	"reflect"
	"strings"
	"time"

	"git.rosy.net.cn/baseapi/utils"
	"git.rosy.net.cn/jx-callback/business/model"
	"git.rosy.net.cn/jx-callback/globals/refutil"
)

func IDCULDFilterMapByStructObject(mapData map[string]interface{}, obj interface{}, isCheckValue bool) (valid map[string]interface{}, invalid map[string]interface{}) {
	// 这里必须用首字母小写，因为是用于访问map，是需要完全匹配的
	return refutil.FilterMapByStructObject(mapData, obj, nil, []string{"id", "createdAt", "updatedAt", "finishedAt", "deletedAt", "syncStatus", "lastOperator"}, isCheckValue)
}

func NormalMakeMapByStructObject(mapData map[string]interface{}, obj interface{}, userName string) (retVal map[string]interface{}) {
	retVal, _ = IDCULDFilterMapByStructObject(mapData, obj, false)
	return retVal
}

func StrictMakeMapByStructObject(mapData map[string]interface{}, obj interface{}, userName string) (retVal map[string]interface{}) {
	retVal, _ = IDCULDFilterMapByStructObject(mapData, obj, true)
	return retVal
}

func IDCULDFilterMapByStructObject2(mapData map[string]interface{}, obj interface{}, objPtr interface{}, isCheckValue bool) (valid map[string]interface{}, invalid map[string]interface{}) {
	return refutil.FilterMapByStructObject(mapData, obj, objPtr, []string{"id", "createdAt", "updatedAt", "finishedAt", "deletedAt", "syncStatus", "lastOperator"}, isCheckValue)
}

//根据传进来的objPtr去修改它的值
func StrictMakeMapByStructObject2(mapData map[string]interface{}, obj interface{}, objPtr interface{}, userName string) (retVal map[string]interface{}) {
	retVal, _ = IDCULDFilterMapByStructObject2(mapData, obj, objPtr, true)
	return retVal
}

func NormalMakeMapByFieldList(mapData map[string]interface{}, fields []string, userName string) (retVal map[string]interface{}) {
	retVal, _ = refutil.FilterMapByFieldList(mapData, fields)
	return retVal
}

func WrapAddIDCULEntity(item interface{}, lastOperator string) interface{} {
	now := time.Now()
	if mapData, ok := item.(map[string]interface{}); ok {
		mapData[model.FieldID] = 0
		mapData[model.FieldCreatedAt] = now
		mapData[model.FieldUpdatedAt] = now
		mapData[model.FieldLastOperator] = lastOperator
	} else {
		value := refutil.CheckAndGetStructValue(item)
		nowValue := reflect.ValueOf(now)
		value.FieldByName(model.FieldID).SetInt(0)
		value.FieldByName(model.FieldCreatedAt).Set(nowValue)
		value.FieldByName(model.FieldUpdatedAt).Set(nowValue)
		value.FieldByName(model.FieldLastOperator).SetString(lastOperator)
	}
	return item
}

func WrapAddIDCULDEntity(item interface{}, lastOperator string) interface{} {
	if mapData, ok := item.(map[string]interface{}); ok {
		mapData[model.FieldDeletedAt] = utils.DefaultTimeValue
	} else {
		value := refutil.CheckAndGetStructValue(item)
		value.FieldByName(model.FieldDeletedAt).Set(reflect.ValueOf(utils.DefaultTimeValue))
	}
	return WrapAddIDCULEntity(item, lastOperator)
}

func WrapUpdateULEntity(item interface{}, lastOperator string) interface{} {
	now := time.Now()
	if mapData, ok := item.(map[string]interface{}); ok {
		mapData[model.FieldUpdatedAt] = now
		mapData[model.FieldLastOperator] = lastOperator
	} else {
		value := refutil.CheckAndGetStructValue(item)
		nowValue := reflect.ValueOf(now)
		value.FieldByName(model.FieldUpdatedAt).Set(nowValue)
		value.FieldByName(model.FieldLastOperator).SetString(lastOperator)
	}
	return item
}

func GenQuestionMarks(count int) (marks string) {
	if count > 0 {
		if count == 1 {
			marks = "?"
		} else {
			builder := &strings.Builder{}
			builder.Grow(1 + (count-1)*3)
			builder.WriteString("?")
			for i := 1; i < count; i++ {
				builder.WriteString(", ?")
			}
			marks = builder.String()
		}
	}
	return marks
}

func ConvertStructFieldPrefix(prefix string) string {
	return prefix
}

func ConvertJsonFieldPrefix(prefix string) string {
	return strings.ToLower(prefix)
}

func ConvertDBFieldPrefix(prefix string) string {
	return strings.ToLower(prefix)
}

func GetVendorThingIDStructField(prefix string) string {
	return ConvertStructFieldPrefix(prefix) + "ID"
}

func GetVendorThingIDJsonField(prefix string) string {
	return ConvertJsonFieldPrefix(prefix) + "ID"
}

func GetVendorThingIDDBField(prefix string) string {
	return ConvertDBFieldPrefix(prefix) + "_id"
}

func GetSyncStatusStructField(prefix string) string {
	return ConvertStructFieldPrefix(prefix) + "SyncStatus"
}

func GetSyncStatusJsonField(prefix string) string {
	return ConvertJsonFieldPrefix(prefix) + "SyncStatus"
}

func GetSyncStatusDBField(prefix string) string {
	return ConvertDBFieldPrefix(prefix) + "_sync_status"
}

func GetVendorPriceStructField(prefix string) string {
	return ConvertStructFieldPrefix(prefix) + "Price"
}

func GetVendorPriceJsonField(prefix string) string {
	return ConvertJsonFieldPrefix(prefix) + "Price"
}

func GetVendorPriceDBField(prefix string) string {
	return ConvertDBFieldPrefix(prefix) + "_price"
}

func GetCategoryIDStructField(prefix string) string {
	return ConvertStructFieldPrefix(prefix) + "CategoryID"
}

func GetCategoryIDJsonField(prefix string) string {
	return ConvertJsonFieldPrefix(prefix) + "CategoryID"
}

func GetCategoryIDDBField(prefix string) string {
	return ConvertDBFieldPrefix(prefix) + "_category_id"
}

func GetVendorLockTimeStructField(prefix string) string {
	return ConvertStructFieldPrefix(prefix) + "LockTime"
}

func value2Value(srcValue, dstValue reflect.Value, copyType int) {
	srcType := srcValue.Type()
	for i := 0; i < srcType.NumField(); i++ {
		fieldName := srcType.Field(i).Name
		if dstFieldvalue := dstValue.FieldByName(fieldName); dstFieldvalue.IsValid() {
			srcFieldValue := srcValue.FieldByName(fieldName)
			if false { //dstFieldvalue.Kind() == reflect.Struct {
				fmt.Printf("%v, %v\n", utils.Format4Output(srcFieldValue.Interface(), false), utils.Format4Output(dstFieldvalue.Interface(), false))
				value2Value(srcFieldValue, dstFieldvalue, copyType)
			} else {
				// fmt.Printf("%v, %v\n", srcFieldValue.Interface(), dstFieldvalue.Interface())
				dstFieldvalue.Set(srcFieldValue)
			}
		}
	}
}

// func copyBetweenNoramAndNullObj(src, dst interface{}, copyType int) {
// 	dstValue := reflect.ValueOf(dst)
// 	if dstValue.Kind() != reflect.Ptr {
// 		panic("ObjNormal2Null dst must be ptr of struct")
// 	}
// 	srcValue := reflect.ValueOf(src)
// 	if srcValue.Kind() == reflect.Ptr {
// 		srcValue = srcValue.Elem()
// 	}
// 	value2Value(srcValue, dstValue.Elem(), copyType)
// }

// func ObjNormal2Null(src, dst interface{}) {
// 	copyBetweenNoramAndNullObj(src, dst, 1)
// }

// func ObjNull2Normal(src, dst interface{}) {
// 	copyBetweenNoramAndNullObj(src, dst, 2)
// }

func IsVendorThingIDEmpty(vendorThingID string) bool {
	return vendorThingID == "" || vendorThingID == "0"
}

func GetAuthType4Vendor(vendorID int) (authType string) {
	authType = ConvertJsonFieldPrefix(model.VendorNames[vendorID])
	if authType != "" {
		authType = "vendor." + authType
	}
	return authType
}
