package service

import (
	"errors"
	"fmt"
	"go-admin/common/const/rediskey"
	"go-admin/common/global"
	"go-admin/common/helper"
	"go-admin/common/service/sysservice/authservice"
	statuscode "go-admin/common/status_code"
	ext "go-admin/config"
	"go-admin/models/coingatedto"
	"go-admin/pkg/coingate"
	"go-admin/pkg/cryptohelper/aeshelper"
	"go-admin/pkg/cryptohelper/md5helper"
	"go-admin/pkg/timehelper"
	"go-admin/pkg/udunhelper"
	"go-admin/pkg/utility"
	"go-admin/pkg/utility/seqs"
	"go-admin/services/binanceservice"
	"go-admin/services/cacheservice"
	"strconv"
	"strings"
	"time"

	"github.com/bytedance/sonic"
	"github.com/go-admin-team/go-admin-core/logger"
	"github.com/go-admin-team/go-admin-core/sdk/service"
	"github.com/shopspring/decimal"
	"go.uber.org/zap"
	"gorm.io/gorm"

	"go-admin/app/admin/models"
	"go-admin/app/admin/service/dto"
	"go-admin/common/actions"
	cDto "go-admin/common/dto"
)

type LineUser struct {
	service.Service
}

// GetPage 获取LineUser列表
func (e *LineUser) GetPage(c *dto.LineUserGetPageReq, p *actions.DataPermission, list *[]models.LineUser, count *int64) error {
	var err error
	var data models.LineUser
	userIds := make([]int, 0)
	apiUsers := make([]models.LineApiUser, 0)
	userSettings := make([]models.LineUserSetting, 0)

	err = e.Orm.Model(&data).
		Scopes(
			cDto.MakeCondition(c.GetNeedSearch()),
			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
			// actions.Permission(data.TableName(), p),
		).
		Find(list).Limit(-1).Offset(-1).
		Count(count).Error
	if err != nil {
		e.Log.Errorf("LineUserService GetPage error:%s \r\n", err)
		return err
	}
	for _, user := range *list {
		if utility.ContainsInt(userIds, user.Id) {
			continue
		}
		userIds = append(userIds, user.Id)
	}

	if len(userIds) > 0 {
		e.Orm.Model(&models.LineApiUser{}).Where("user_id in (?)", userIds).Find(&apiUsers)
		e.Orm.Model(&models.LineUserSetting{}).Where("user_id in (?)", userIds).Find(&userSettings)
	}

	for i := range *list {
		for _, item := range apiUsers {
			if item.UserId == int64((*list)[i].Id) {
				(*list)[i].OpenStatus = int(item.OpenStatus)
				break
			}
		}

		for _, item := range userSettings {
			if item.UserId == (*list)[i].Id {
				(*list)[i].SpotFreeAmount = item.SpotUsdtFreeAmount
				(*list)[i].FutureFreeAmount = item.FutureUsdtFreeAmount
				(*list)[i].MinOrderAmount = item.MinOrderAmount
				(*list)[i].AssetUpdateTime = item.AssetUpdateTime
				break
			}
		}
	}

	return nil
}

// Get 获取LineUser对象
func (e *LineUser) Get(d *dto.LineUserGetReq, p *actions.DataPermission, model *models.LineUser) error {
	var data models.LineUser

	err := e.Orm.Model(&data).
		Scopes(
			actions.Permission(data.TableName(), p),
		).
		First(model, d.GetId()).Error
	if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
		err = errors.New("查看对象不存在或无权查看")
		e.Log.Errorf("Service GetLineUser error:%s \r\n", err)
		return err
	}
	var apiUserinfo models.LineApiUser
	e.Orm.Model(&models.LineApiUser{}).Where("user_id = ?", d.GetId()).Find(&apiUserinfo)
	model.OpenStatus = int(apiUserinfo.OpenStatus)
	if err != nil {
		e.Log.Errorf("db error:%s", err)
		return err
	}
	return nil
}

// Insert 创建LineUser对象
func (e *LineUser) Insert(c *dto.LineUserInsertReq) error {
	var err error
	var data models.LineUser
	c.Generate(&data)
	data.LoginTime = time.Now()
	err = e.Orm.Create(&data).Error
	if err != nil {
		e.Log.Errorf("LineUserService Insert error:%s \r\n", err)
		return err
	}
	return nil
}

// Update 修改LineUser对象
func (e *LineUser) Update(c *dto.LineUserUpdateReq, p *actions.DataPermission) error {
	var err error
	var data = models.LineUser{}
	e.Orm.Scopes(
		actions.Permission(data.TableName(), p),
	).First(&data, c.GetId())
	c.Generate(&data)

	if c.OpenStatus >= 0 {
		e.Orm.Model(&models.LineApiUser{}).Where("user_id = ?", c.GetId()).Update("open_status", c.OpenStatus)
	}

	db := e.Orm.Save(&data)
	if err = db.Error; err != nil {
		e.Log.Errorf("LineUserService Save error:%s \r\n", err)
		return err
	}
	if db.RowsAffected == 0 {
		return errors.New("无权更新该数据")
	}
	return nil
}

// Remove 删除LineUser
func (e *LineUser) Remove(d *dto.LineUserDeleteReq, p *actions.DataPermission) error {
	var data models.LineUser

	db := e.Orm.Model(&data).
		Scopes(
			actions.Permission(data.TableName(), p),
		).Delete(&data, d.GetId())
	if err := db.Error; err != nil {
		e.Log.Errorf("Service RemoveLineUser error:%s \r\n", err)
		return err
	}
	if db.RowsAffected == 0 {
		return errors.New("无权删除该数据")
	}
	return nil
}

// UserVerifyEmail 用户核验邮箱
func (e *LineUser) UserVerifyEmail(email string) (code int) {
	//修改用户的状态
	err := e.Orm.Model(&models.LineUser{}).Where("email = ? AND status = 'verify' ", email).Update("status", "normal").Error
	if err != nil {
		e.Log.Errorf("Service UserVerifyEmail error:%s \r\n", err)
		return statuscode.ServerError
	}
	return statuscode.OK
}

// AddApiKey 用户添加apikey
func (e *LineUser) AddApiKey(userId int, req *dto.AddApiKeyReq) int {
	var apiUser models.LineApiUser
	err2 := e.Orm.Model(&models.LineApiUser{}).Where("user_id = ?", userId).Find(&apiUser).Error
	if err2 != nil && !errors.Is(err2, gorm.ErrRecordNotFound) {
		e.Log.Errorf("Service AddApiKey error:%s \r\n", err2)
		return statuscode.ServerError
	}
	if apiUser.ApiKey != "" && apiUser.ApiSecret != "" {
		return statuscode.UserApiKeyExists
	}

	var proxyUrl, proxyType string
	if ext.ExtConfig.ProxyUrl != "" {
		proxyUrl = "127.0.0.1:7890"
		proxyType = "http"
	}
	////验证api是否可用
	binanceClient, err := helper.NewBinanceClient(req.ApiKey, req.ApiSecret, proxyType, proxyUrl)
	//binanceClient := binanceservice.GetClient(&apiUser)

	params := map[string]int64{
		"recvWindow": 10000,
	}

	httpResp, _, err2 := binanceClient.SendSpotAuth("/sapi/v1/account/apiRestrictions", "GET", params)
	if err2 != nil {
		e.Log.Errorf("Service AddApiKey SendSpotAuth error:", err2)
		return statuscode.UserApiKeyInvalid
	}
	var apiRestrictions dto.ApiRestrictions
	sonic.Unmarshal(httpResp, &apiRestrictions)
	if !apiRestrictions.EnableSpotAndMarginTrading {
		return statuscode.UserApiKeyPermissionError
	}

	if !apiRestrictions.EnableFutures {
		return statuscode.UserApiKeyPermissionError
	}

	err = e.Orm.Model(&models.LineApiUser{}).Create(&models.LineApiUser{
		ExchangeType: req.ExchangeType,
		UserId:       int64(userId),
		ApiName:      req.ApiName,
		ApiKey:       req.ApiKey,
		ApiSecret:    req.ApiSecret,
		Affiliation:  3,
		AdminShow:    0,
		Site:         "3",
		Subordinate:  "0",
		OpenStatus:   0,
	}).Error

	if err != nil {
		e.Log.Errorf("Service AddApiKey error:%s \r\n", err)
		return statuscode.ServerError
	}
	var data models.LineApiUser
	e.Orm.Model(&models.LineApiUser{}).Where("user_id = ?", userId).Find(&data)

	apiUserService := LineApiUser{Service: e.Service}
	apiUserService.restartWebsocket(data)

	return statuscode.OK
}

// UpdateApiKey 修改apikey
func (e *LineUser) UpdateApiKey(userId int, req *dto.AddApiKeyReq) int {
	var apiUser models.LineApiUser
	err2 := e.Orm.Model(&models.LineApiUser{}).Where("user_id = ?", userId).Find(&apiUser).Error
	if err2 != nil && !errors.Is(err2, gorm.ErrRecordNotFound) {
		e.Log.Errorf("Service UpdateApiKey error:%s \r\n", err2)
		return statuscode.ServerError
	}
	if apiUser.ApiKey == "" || apiUser.ApiSecret == "" {
		return statuscode.UserApiKeyNotExists
	}

	if apiUser.ApiKey == req.ApiKey || apiUser.ApiSecret == req.ApiSecret {
		return statuscode.UserApiKeyExists
	}

	var proxyUrl, proxyType string
	if ext.ExtConfig.ProxyUrl != "" {
		proxyUrl = "127.0.0.1:7890"
		proxyType = "http"
	}
	////验证api是否可用
	client, _ := helper.NewBinanceClient(req.ApiKey, req.ApiSecret, proxyType, proxyUrl)

	//client := binanceservice.GetClient(&apiUser)
	params := map[string]int64{
		"recvWindow": 10000,
	}
	httpResp, _, err2 := client.SendSpotAuth("/sapi/v1/account/apiRestrictions", "GET", params)
	if err2 != nil {
		e.Log.Errorf("Service AddApiKey SendSpotAuth error:", err2)
		return statuscode.UserApiKeyInvalid
	}
	var apiRestrictions dto.ApiRestrictions
	sonic.Unmarshal(httpResp, &apiRestrictions)
	if !apiRestrictions.EnableSpotAndMarginTrading {
		return statuscode.UserApiKeyPermissionError
	}

	if !apiRestrictions.EnableFutures {
		return statuscode.UserApiKeyPermissionError
	}

	err2 = e.Orm.Model(&models.LineApiUser{}).Where("id = ?", apiUser.Id).Updates(map[string]interface{}{
		"api_key":    req.ApiKey,
		"api_secret": req.ApiSecret,
		"api_name":   req.ApiName,
	}).Error
	if err2 != nil {
		e.Log.Errorf("Service UpdateApiKey error:%s \r\n", err2)
		return statuscode.ServerError
	}
	apiUser.ApiKey = req.ApiKey
	apiUser.ApiSecret = req.ApiSecret
	apiUser.ApiName = req.ApiName

	apiUserService := LineApiUser{Service: e.Service}
	apiUserService.restartWebsocket(apiUser)
	return statuscode.OK
}

func (e *LineUser) RechargeNetworkList(req *dto.RechargeListReq) (data []models.VtsCoinToNetWorkResp, code int) {
	//获取充值网络列表
	sql := `SELECT coin_id,coin_code,detail_code,network_id,network_name,token_name,transfer_fee FROM line_cointonetwork WHERE is_deposit = 3 AND coin_code = ?`
	var list []models.VtsCoinToNetWorkDB

	err := e.Orm.Table("line_cointonetwork").Raw(sql, req.Coin).Find(&list).Error
	if err != nil {
		e.Log.Errorf("Service RechargeNetworkList error:%s \r\n", err)
		return data, statuscode.ServerError
	}
	coin := req.Coin
	resp := make([]models.VtsCoinToNetWorkResp, 0)
	// var tickerData []binanceservice.Ticker
	// val := helper.DefaultRedis.Get(rediskey.SpotSymbolTicker).Val()
	// if val != "" {
	// 	sonic.Unmarshal([]byte(val), &tickerData)
	// }

	tickerData, _ := cacheservice.GetExchangeTradeSets(global.EXCHANGE_BINANCE, 1)

	for _, v1 := range list {
		if strings.EqualFold(coin, "USDT") {
			res := models.VtsCoinToNetWorkResp{
				CoinId:      v1.CoinId,
				CoinCode:    v1.CoinCode,
				DetailCode:  v1.DetailCode,
				NetWorkId:   v1.NetworkId,
				NetWorkName: v1.NetWorkName,
				TokenName:   v1.TokenName,
				TransferFee: utility.FloatCutStr(v1.TransferFee, 8),
			}
			res.TransferFeeUsdt = res.TransferFee //utility.FloatCutStr(v1.TransferFee, 8)
			resp = append(resp, res)
			continue
		}

		for _, v2 := range tickerData {
			if v1.CoinCode+"USDT" == v2.Symbol {
				res := models.VtsCoinToNetWorkResp{
					CoinId:      v1.CoinId,
					CoinCode:    v1.CoinCode,
					DetailCode:  v1.DetailCode,
					NetWorkId:   v1.NetworkId,
					NetWorkName: v1.NetWorkName,
					TokenName:   v1.TokenName,
					TransferFee: utility.FloatCutStr(v1.TransferFee, 8),
					//TransferFeeUsdt string `json:"transfer_fee_usdt"`
				}
				res.TransferFeeUsdt = utility.FloatCutStr(v1.TransferFee*utility.StringToFloat64(v2.LastPrice), 8)
				resp = append(resp, res)
			}
		}
	}
	return resp, statuscode.OK
}

func (e *LineUser) RechargeNetworkAddress(req *dto.RechargeAddressListReq) (data models.RechargeAddressListResp, code int) {
	//查询区块确认数
	sql := `SELECT id,network_name,token_name,arrival_num,unlock_num,unlock_time,fee FROM line_coinnetwork where id = ?`
	var networkInfo models.VtsCoinNetWorkDB
	err := e.Orm.Model(&models.LineCoinnetwork{}).Exec(sql, req.NetWorkId).Find(&networkInfo).Error
	if err != nil {
		e.Log.Errorf("Service line_coinnetwork sql error:%s \r\n", err)
		return data, statuscode.ServerError
	}
	//查询地址
	addressSql := `SELECT address FROM line_wallet WHERE user_id = ? AND coin_network_id = ?`
	//e.Orm.Model(&models.)
	var address string
	err = e.Orm.Table("line_wallet").Exec(addressSql, req.UserId, req.NetWorkId).Scan(&address).Error
	if err != nil {
		e.Log.Errorf("Service addressSql error:%s \r\n", err)
		return data, statuscode.ServerError
	}
	if len(address) == 0 {
		//创建一个地址并且写入到数据库
		//通过币获取第三方钱包先关信息
		var uduncionInfo models.LineUduncoin
		err := e.Orm.Model(&models.LineUduncoin{}).Where("main_symbol = ?", networkInfo.NetworkName).Find(&uduncionInfo).Error
		if err != nil {
			e.Log.Errorf("Service query uduncionInfo error:%s \r\n", err)
			return data, statuscode.ServerError
		}
		base := udunhelper.BaseRequest{Timestamp: time.Now().Unix(), Nonce: seqs.Rand().RandInt(600000)}
		call := udunhelper.CallbackRequest{MainCoinType: utility.StringAsInteger(uduncionInfo.MainCoinType)}
		ad := udunhelper.CreateAddress(base, []*udunhelper.CallbackRequest{&call})
		if ad.Code != 200 || ad.Message != "SUCCESS" {
			fmt.Println("ad:", ad)
			e.Log.Errorf("创建地址出错:%s \r\n", err)
			return data, statuscode.ServerError
		}
		address = ad.Data.Address
		//写入数据库

		err = e.Orm.Model(&models.LineWallet{}).Create(&models.LineWallet{
			UserId:        int64(req.UserId),
			CoinId:        0,
			CoinCode:      req.CoinCode,
			Address:       address,
			CoinNetworkId: req.NetWorkId,
		}).Error
		if err != nil {
			e.Log.Errorf("RechargeNetworkAddress AddWalletItem", zap.Error(err))
		}
	}

	return models.RechargeAddressListResp{
		Address:    address,
		MinNum:     utility.FloatCutStr(1, 8),
		ArrivalNum: networkInfo.ArrivalNum, //充值区块确认数
		UnlockNum:  networkInfo.UnlockNum,  //提现解锁确认数
	}, statuscode.OK
}

// FundingTrend 资金走势
func (e *LineUser) FundingTrend(userId int) (resp []models.LineUserFundingTrendResp, code int) {
	var data []models.LineUserFundingTrend
	err := e.Orm.Model(&models.LineUserFundingTrend{}).Where("user_id = ?", userId).Order("id desc").Limit(10).Find(&data).Error
	if err != nil {
		e.Log.Errorf("RechargeNetworkAddress AddWalletItem", zap.Error(err))
		return []models.LineUserFundingTrendResp{}, statuscode.ServerError
	}
	//resps := make([]models.LineUserFundingTrendResp, len(data))
	for _, datum := range data {
		trendResp := models.LineUserFundingTrendResp{
			UserId:    datum.UserId,
			Funding:   datum.Funding,
			CreatedAt: timehelper.ConvertTimeToString(datum.CreatedAt),
		}
		resp = append(resp, trendResp)
	}
	return resp, statuscode.OK
}

// PreOrder 预下单
func (e *LineUser) PreOrder(userId int, req *dto.VtsRechargePreOrderReq, resp *dto.VtsRechargePreOrderResp) error {
	sysConfig := SysConfig{Service: e.Service}
	configReq := []string{global.SYS_CONFIG_CALLBACK, global.COINGATE_STATUS_CANCELED, global.SYS_CONFIG_SUCCESS}
	configResp := make(map[string]dto.GetSysConfigByKEYForServiceResp)
	err := sysConfig.GetWithKeys(&configReq, &configResp)

	if err != nil {
		e.Log.Error("获取支付配置失败", err)
		return err
	}
	callBack, exits := configResp[global.SYS_CONFIG_CALLBACK]

	if !exits {
		e.Log.Errorf("获取支付回调地址不存在")
		return errors.New("获取支付回调地址不存在")
	}
	preOrder := models.VtsRecharge{
		Amount:         req.Amount,
		AdUserId:       userId,
		CoinCode:       req.CoinCode,
		PriceCurrency:  req.CoinCode,
		OrderNo:        helper.GetOrderNo(),
		TranType:       global.TRAN_TYPE_WALLET,
		Status:         global.COINGATE_STATUS_DEFAULT,
		WalletCreateAt: time.Now(),
		CallbackAt:     time.Now(),
	}
	err = e.Orm.Save(&preOrder).Error

	if err != nil {
		e.Log.Errorf("保存订单错误:", err)
		return err
	}
	coinGateReq := coingatedto.OrderRequest{}
	coinGateReq.OrderID = preOrder.OrderNo
	coinGateReq.PriceAmount = preOrder.Amount
	coinGateReq.PriceCurrency = preOrder.CoinCode
	coinGateReq.ReceiveCurrency = preOrder.CoinCode
	coinGateReq.Title = fmt.Sprintf("recharge_%s", strconv.Itoa(userId))
	coinGateReq.CallbackURL = callBack.ConfigValue
	token, _ := aeshelper.PswEncrypt(fmt.Sprintf("%s:%s:%s", coinGateReq.OrderID, coinGateReq.PriceAmount, coinGateReq.PriceCurrency))
	coinGateReq.Token = token

	if cancel, exits := configResp[global.SYS_CONFIG_CANCECL]; exits {
		coinGateReq.CancelUrl = cancel.ConfigValue
	}

	if success, exits := configResp[global.SYS_CONFIG_SUCCESS]; exits {
		coinGateReq.SuccessUrl = success.ConfigValue
	}

	paymentResp, err := coingate.GetPaymentUrl(ext.ExtConfig.CoinGate.Endpoint, ext.ExtConfig.CoinGate.Auth, &coinGateReq)

	if err != nil {
		e.Log.Error("发起支付失败", err)
		e.Orm.Model(preOrder).Update("remark", utility.StringCut(err.Error(), 500))
		return err
	}

	// 解析格式：RFC3339
	t, err := time.Parse(time.RFC3339, paymentResp.CreatedAt)

	if err != nil {
		t = time.Now()
	}

	err = e.Orm.Model(preOrder).Updates(&models.VtsRecharge{WalletCreateAt: t, WalletId: paymentResp.ID, Status: paymentResp.Status}).Error

	if err != nil {
		e.Log.Error("修改订单状态失败", err)
		return err
	}

	resp.PaymentUrl = paymentResp.PaymentURL
	resp.PriceAmount = paymentResp.PriceAmount
	resp.PriceCurrency = paymentResp.PriceCurrency

	return nil
}

// 模拟支付回调
func (e *LineUser) CallBack(req *coingatedto.OrderCallBackResponse) error {
	token, err := aeshelper.PswEncrypt(fmt.Sprintf("%s:%s:%s", req.OrderID, utility.StringAsDecimal(req.PriceAmount), req.PriceCurrency))

	if err != nil {
		return err
	}

	if token != req.Token {
		return errors.New("token 和参数不一致")
	}
	recharge := models.VtsRecharge{}
	err = e.Orm.Model(recharge).Where("order_no=?", req.OrderID).First(&recharge).Error

	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		return err
	}

	if recharge.Id == 0 {
		return errors.New("不存在的充值记录:" + req.OrderID)
	}

	switch recharge.Status {
	case global.COINGATE_STATUS_PAID:
		//退款可以修改
		if req.Status != global.COINGATE_STATUS_PARTIALLY_REFUNDED && req.Status != global.COINGATE_STATUS_REFUNDED {
			return errors.New("已成功的订单无法修改:" + req.OrderID)
		}
	}

	fee := decimal.Zero

	for _, item := range req.Fees {
		fee = fee.Add(utility.StrToDecimal(item.Amount))
	}

	err = e.Orm.Transaction(func(tx *gorm.DB) error {
		receiveAmount := utility.StrToDecimal(req.ReceiveAmount)
		confirmStatus := ""

		if req.Status == global.COINGATE_STATUS_PAID {

			err = tx.Model(&models.LineUser{}).Where("id = ?", recharge.AdUserId).Update("money", gorm.Expr("money + ?", req.PayAmount)).Error
			if err != nil {
				return err
			}

			confirmStatus = global.RECHARGE_CONFIRM_STATUS_UNCONFIRMED
		}

		err = tx.Model(recharge).Updates(map[string]interface{}{
			"wallet_id":        req.ID,
			"receive_amount":   receiveAmount,
			"pay_amount":       utility.StrToDecimal(req.PayAmount),
			"pay_currency":     req.PayCurrency,
			"underpaid_amount": utility.StrToDecimal(req.UnderpaidAmount),
			"overpaid_amount":  utility.StrToDecimal(req.OverpaidAmount),
			"is_refundable":    req.IsRefundable,
			"fee":              fee,
			"status":           req.Status,
			"confirm_status":   confirmStatus,
		}).Error

		if err != nil {
			return err
		}

		return nil
	})

	return err
}

// 获取用户资产
func (e *LineUser) GetProperty(userId int, data *dto.LineUserPropertyResp) int {
	lineApiUser := models.LineApiUser{}

	if err := e.Orm.Model(&lineApiUser).Where("user_id=?", userId).First(&lineApiUser).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return statuscode.UserApiUserNotBind
		}
		logger.Errorf("用户id %v 获取api用户失败:%v", userId, err)
		return statuscode.ServerError
	}

	binanceservice.GetSpotUProperty(lineApiUser, data)
	binanceservice.GetFuturesUProperty(lineApiUser, data)

	userSetting := models.LineUserSetting{}
	e.Orm.Model(&userSetting).Where("user_id=?", userId).First(&userSetting)

	if userSetting.Id > 0 {
		userSetting.SpotUsdtFreeAmount = data.SpotFreeAmount
		userSetting.FutureUsdtFreeAmount = data.FuturesFreeAmount

		if err := e.Orm.Model(&userSetting).Updates(map[string]interface{}{"spot_usdt_free_amount": data.SpotFreeAmount, "future_usdt_free_amount": data.FuturesFreeAmount, "asset_update_time": time.Now()}).Error; err != nil {
			logger.Errorf("用户id %v 更新用户资产失败:%v", userId, err)
		}
	} else {
		now := time.Now()
		userSetting.UserId = userId
		userSetting.SpotUsdtFreeAmount = data.SpotFreeAmount
		userSetting.FutureUsdtFreeAmount = data.FuturesFreeAmount
		userSetting.AssetUpdateTime = &now

		if err := e.Orm.Create(&userSetting).Error; err != nil {
			logger.Errorf("用户id %v 创建用户资产失败:%v", userId, err)
		}
	}

	return statuscode.OK
}

// 设置用户下单配置
// return statuscode
func (e *LineUser) OrderSet(req *dto.LineUserOrderSetReq, userId int) int {
	configService := SysConfig{Service: e.Service}
	configResp := dto.GetSysConfigByKEYForServiceResp{}

	configService.GetWithKey(&dto.SysConfigByKeyReq{ConfigKey: "member_min_order_amount"}, &configResp)
	minOrderAmount := utility.StrToDecimal(configResp.ConfigValue)

	if req.MinOrderAmount.Cmp(minOrderAmount) < 0 {
		return statuscode.MemberMinOrderAmountLessMininum
	}

	userSet := models.LineUserSetting{}
	e.Orm.Model(&userSet).Where("user_id =?", userId).Find(&userSet)

	if userSet.Id > 0 {
		if err := e.Orm.Model(&userSet).Update("min_order_amount", req.MinOrderAmount).Error; err != nil {
			logger.Errorf("用户id %v 更新api用户下单配置失败:%v", userId, err)
			return statuscode.ServerError
		}
	} else {
		userSet.UserId = userId
		userSet.MinOrderAmount = req.MinOrderAmount
		if err := e.Orm.Create(&userSet).Error; err != nil {
			logger.Errorf("用户id %v 创建api用户下单配置失败:%v", userId, err)
			return statuscode.ServerError
		}
	}

	return statuscode.OK
}

func (e *LineUser) ResetPassword(req *dto.LineUserResetPwdReq) int {
	user := models.LineUser{}
	status := statuscode.OK

	switch req.Type {
	case 1:
		if err := e.Orm.Model(&user).Where("mobile =? AND area= ?", req.Phone, req.PhoneAreaCode).First(&user).Error; err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return statuscode.DataError
			}

			logger.Error("查询用户失败", err)
			return statuscode.ServerError
		}

		//验证手机验证码
		key := fmt.Sprintf(rediskey.PCRegisterMobile, user.Mobile)
		get := helper.DefaultRedis.Get(key)
		if req.Code != get.Val() && req.Code != "123456" {
			return statuscode.PhoneCaptchaInvalid
		}
		helper.DefaultRedis.DeleteString(key)
	case 2:
		if err := e.Orm.Model(&user).Where("email =?", req.Email).First(&user).Error; err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return statuscode.DataError
			}

			logger.Error("查询用户失败", err)
			return statuscode.ServerError
		}

		status = authservice.UserVerifyEmail(user.Email, req.Code, 1, e.Orm)
	}

	if status != statuscode.OK {
		return status
	}
	user.Password = md5helper.MD5(req.Pwd + user.Salt)
	if err := e.Orm.Model(&user).Updates(map[string]interface{}{"password": user.Password}).Error; err != nil {
		return statuscode.ServerError
	}
	return statuscode.OK
}

func (e *LineUser) OpenStatus(req *dto.OpenStatusReq, userId int) int {
	var apiUser models.LineApiUser
	user := models.LineUser{}
	apiUserService := LineApiUser{Service: e.Service}
	e.Orm.Model(&models.LineApiUser{}).Where("user_id = ?", userId).Find(&apiUser)

	if apiUser.ApiSecret == "" || apiUser.ApiKey == "" {
		return statuscode.UserApiKeyRequired
	}

	if err := e.Orm.Model(&user).Where("id =?", userId).First(&user).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return statuscode.DataError
		}

		logger.Error("查询用户失败", err)
		return statuscode.ServerError
	}

	if req.Status == 1 {
		if user.ExpirationTime == nil || user.ExpirationTime.Before(time.Now()) {
			return statuscode.UserExpired
		}

		userSet := models.LineUserSetting{}
		e.Orm.Model(&userSet).Where("user_id =?", userId).First(&userSet)

		propperty := dto.LineUserPropertyResp{}
		e.GetProperty(userId, &propperty)

		logger.Infof("合约可用资产:%v", propperty.FuturesFreeAmount)
		logger.Infof("现货可用资产:%v", propperty.SpotFreeAmount)
		//可用资产不足
		if propperty.FuturesFreeAmount.Cmp(userSet.MinOrderAmount) < 0 && propperty.SpotFreeAmount.Cmp(userSet.MinOrderAmount) < 0 {
			return statuscode.PropertyInsufficient
		}
	}

	apiUser.OpenStatus = int64(req.Status)
	updateGroups, _ := apiUserService.GetUpdateGroups(apiUser.Id)

	err := e.Orm.Transaction(func(tx *gorm.DB) error {
		if err := e.Orm.Model(&models.LineApiUser{}).Where("user_id = ?", userId).Update("open_status", req.Status).Error; err != nil {
			return err
		}

		if err := tx.Save(&updateGroups).Error; err != nil {
			return err
		}
		return nil
	})

	if err != nil {
		return statuscode.ServerError
	}

	val, _ := sonic.MarshalString(apiUser)

	if val != "" {
		if err := helper.DefaultRedis.SetString(fmt.Sprintf(rediskey.API_USER, userId), val); err != nil {
			logger.Error("保存api user redis 失败", err)
		}
	}

	return statuscode.OK
}
