package financial_center

import (
	"applet/app/db"
	"applet/app/e"
	md "applet/app/md/financial_center"
	svc "applet/app/svc/financial_center"
	"applet/app/utils"
	"code.fnuoos.com/EggPlanet/egg_models.git/src/implement"
	"code.fnuoos.com/EggPlanet/egg_models.git/src/model"
	"code.fnuoos.com/EggPlanet/egg_system_rules.git/enum"
	md3 "code.fnuoos.com/EggPlanet/egg_system_rules.git/md"
	"code.fnuoos.com/EggPlanet/egg_system_rules.git/rule"
	md2 "code.fnuoos.com/EggPlanet/egg_system_rules.git/rule/egg_energy/md"
	"code.fnuoos.com/go_rely_warehouse/zyos_go_mq.git/rabbit"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/copier"
	"strings"
	"time"
)

// GetWithdrawSetting
// @Summary      财务中心-提现-基础设置(获取)
// @Tags         提现
// @Description  基础设置(获取)
// @Accept       json
// @Produce      json
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Success      200   {object}   md.GetWithdrawSettingResp  	"具体数据"
// @Failure      400   {object}   md.Response              	"具体错误"
// @Router       /api/financialCenter/withdraw/setting [get]
func GetWithdrawSetting(c *gin.Context) {

	// 等级列表
	levelDb := implement.NewUserLevelDb(db.Db)
	levels, err1 := levelDb.UserLevelAllByAsc()
	if err1 != nil {
		e.OutErr(c, e.ERR_DB_ORM, err1.Error())
		return
	}
	levelsList := make([]map[string]interface{}, 0)
	levelsMap := make(map[int]string)
	for _, level := range levels {
		levelsList = append(levelsList, map[string]interface{}{
			"id":   level.Id,
			"name": level.LevelName,
		})
		levelsMap[level.Id] = level.LevelName
	}

	settingDb := implement.NewFinWithdrawSettingDb(db.Db)
	setting, err := settingDb.FinWithdrawSettingGetOne()
	if err != nil {
		e.OutErr(c, e.ERR_DB_ORM, err.Error())
		return
	}
	// 不存在则初始化
	var emptyNum []string
	if setting == nil {
		now := time.Now()
		frequency := md2.WithdrawFrequencySettingStruct{
			Duration: 1,
			Num:      emptyNum,
		}
		withdrawFeeSet := md2.WithdrawFeeSetStruct{
			Kind:  1,
			Value: 0,
		}
		firstWithdrawSet := md2.FirstWithdrawSet{
			IsNeedRealName:           0,
			FirstWithdrawAmountLimit: "",
		}
		frequencyStr := utils.SerializeStr(frequency)
		withdrawFeeSetStr := utils.SerializeStr(withdrawFeeSet)
		firstWithdrawSetStr := utils.SerializeStr(firstWithdrawSet)
		m := model.FinWithdrawSetting{
			FrequencySet:            frequencyStr,
			WithdrawType:            1,
			VipLevelLimit:           0,
			IsRealName:              0,
			WithdrawNumsLimit:       0,
			WithdrawAmountLimit:     "",
			WithdrawMultipleLimit:   "",
			IsSupportDecimalPoint:   0,
			IsAuto:                  0,
			WithdrawTimeInterval:    "00:00-00:00",
			WithdrawFeeSet:          withdrawFeeSetStr,
			PendingOrdersIsCanApply: 0,
			ConditionIsOpen:         0,
			FirstWithdrawSet:        firstWithdrawSetStr,
			CreateAt:                now.Format("2006-01-02 15:04:05"),
		}
		_, err2 := settingDb.FinWithdrawSettingInsert(&m)
		if err2 != nil {
			e.OutErr(c, e.ERR_DB_ORM, err2.Error())
			return
		}

		setting, err = settingDb.FinWithdrawSettingGetOne()
		if err != nil {
			e.OutErr(c, e.ERR_DB_ORM, err.Error())
			return
		}
	}
	var frequency md2.WithdrawFrequencySettingStruct
	var withdrawFeeSet md2.WithdrawFeeSetStruct
	var firstWithdrawSet md2.FirstWithdrawSet
	utils.Unserialize([]byte(setting.FrequencySet), &frequency)
	utils.Unserialize([]byte(setting.WithdrawFeeSet), &withdrawFeeSet)
	utils.Unserialize([]byte(setting.FirstWithdrawSet), &firstWithdrawSet)
	withdrawTimeIntervals := strings.Split(setting.WithdrawTimeInterval, "-")
	withdrawTimeInterval := md2.WithdrawTimeIntervalStruct{
		StartAt: withdrawTimeIntervals[0],
		EndAt:   withdrawTimeIntervals[1],
	}
	resp := md.GetWithdrawSettingResp{
		Id:                      setting.Id,
		FrequencySet:            frequency,
		WithdrawType:            setting.WithdrawType,
		VipLevelLimit:           setting.VipLevelLimit,
		IsRealName:              setting.IsRealName,
		WithdrawNumsLimit:       setting.WithdrawNumsLimit,
		WithdrawAmountLimit:     setting.WithdrawAmountLimit,
		WithdrawMultipleLimit:   setting.WithdrawMultipleLimit,
		IsSupportDecimalPoint:   setting.IsSupportDecimalPoint,
		IsAuto:                  setting.IsAuto,
		IsAutoAmountLimit:       setting.IsAutoAmountLimit,
		WithdrawTimeInterval:    withdrawTimeInterval,
		WithdrawFeeSet:          withdrawFeeSet,
		FirstWithdrawSet:        firstWithdrawSet,
		PendingOrdersIsCanApply: setting.PendingOrdersIsCanApply,
		ConditionIsOpen:         setting.ConditionIsOpen,
		LevelList:               levelsList,
	}

	e.OutSuc(c, resp, nil)
}

// UpdateWithdrawSetting
// @Summary      财务中心-提现-基础设置(更新)
// @Tags         提现
// @Description  基础设置(更新)
// @Accept       json
// @Produce      json
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Param    req    body	md.UpdateWithdrawSettingReq 	true  "id 必填"
// @Success      200   {int}   	"修改数据条数"
// @Failure      400   {object}   md.Response              	"具体错误"
// @Router       /api/financialCenter/withdraw/updateWithdrawSetting [POST]
func UpdateWithdrawSetting(c *gin.Context) {
	var req *md.UpdateWithdrawSettingReq
	if err1 := c.ShouldBindJSON(&req); err1 != nil {
		e.OutErr(c, e.ERR_INVALID_ARGS, err1.Error())
		return
	}
	if req.WithdrawTimeInterval.StartAt != "" {
		res := utils.IsTimeFormat(req.WithdrawTimeInterval.StartAt)
		if req.WithdrawTimeInterval.StartAt > "23:59" {
			res = false
		}
		if !res {
			e.OutErr(c, e.ERR_INVALID_ARGS, errors.New("开始时间应为 xx:xx 且不超过 23:59").Error())
			return
		}
	}
	if req.WithdrawTimeInterval.EndAt != "" {
		res := utils.IsTimeFormat(req.WithdrawTimeInterval.EndAt)
		if req.WithdrawTimeInterval.EndAt > "23:59" {
			res = false
		}
		if !res {
			e.OutErr(c, e.ERR_INVALID_ARGS, errors.New("结束时间应为 xx:xx 且不超过 23:59").Error())
			return
		}
	}

	frequencyStr := utils.SerializeStr(req.FrequencySet)
	withdrawFeeSetStr := utils.SerializeStr(req.WithdrawFeeSet)
	firstWithdrawSetStr := utils.SerializeStr(req.FirstWithdrawSet)
	var withdrawTimeInterval []string
	withdrawTimeInterval = append(withdrawTimeInterval, req.WithdrawTimeInterval.StartAt)
	withdrawTimeInterval = append(withdrawTimeInterval, req.WithdrawTimeInterval.EndAt)
	withdrawTimeIntervalStr := strings.Join(withdrawTimeInterval, "-")
	m := model.FinWithdrawSetting{
		Id:                      req.Id,
		FrequencySet:            frequencyStr,
		WithdrawType:            req.WithdrawType,
		VipLevelLimit:           req.VipLevelLimit,
		IsRealName:              req.IsRealName,
		WithdrawNumsLimit:       req.WithdrawNumsLimit,
		WithdrawAmountLimit:     req.WithdrawAmountLimit,
		WithdrawMultipleLimit:   req.WithdrawMultipleLimit,
		IsSupportDecimalPoint:   req.IsSupportDecimalPoint,
		IsAuto:                  req.IsAuto,
		IsAutoAmountLimit:       req.IsAutoAmountLimit,
		WithdrawTimeInterval:    withdrawTimeIntervalStr,
		WithdrawFeeSet:          withdrawFeeSetStr,
		PendingOrdersIsCanApply: req.PendingOrdersIsCanApply,
		ConditionIsOpen:         req.ConditionIsOpen,
		FirstWithdrawSet:        firstWithdrawSetStr,
	}

	forceColumns := []string{"withdraw_type", "is_real_name", "withdraw_nums_limit",
		"withdraw_amount_limit", "withdraw_multiple_limit", "is_support_decimal_point",
		"is_auto", "first_withdraw_set", "is_auto_amount_limit", "pending_orders_is_can_apply",
		"condition_is_open",
	}
	settingDb := implement.NewFinWithdrawSettingDb(db.Db)
	affected, err := settingDb.FinWithdrawSettingUpdate(req.Id, &m, forceColumns...)
	if err != nil {
		e.OutErr(c, e.ERR_DB_ORM, err.Error())
		return
	}
	e.OutSuc(c, affected, nil)
}

// GetWithdrawApplyList
// @Summary      财务中心-提现-提现申请列表(获取)
// @Tags         提现
// @Description  提现申请列表(获取)
// @Accept       json
// @Produce      json
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Param    req    body	md.GetWithdrawApplyListReq 	false  "筛选条件"
// @Success      200   {object}   	md.GetWithdrawApplyListResp "具体数据"
// @Failure      400   {object}   md.Response              	"具体错误"
// @Router       /api/financialCenter/withdraw/applyList [POST]
func GetWithdrawApplyList(c *gin.Context) {
	var req *md.GetWithdrawApplyListReq
	if err1 := c.ShouldBindJSON(&req); err1 != nil {
		e.OutErr(c, e.ERR_INVALID_ARGS, err1.Error())
		return
	}

	levelDb := implement.NewUserLevelDb(db.Db)
	levels, err1 := levelDb.UserLevelAllByAsc()
	if err1 != nil {
		e.OutErr(c, e.ERR_DB_ORM, err1.Error())
		return
	}
	levelsList := make([]map[string]interface{}, 0)
	levelsMap := make(map[int]string)
	for _, level := range levels {
		levelsList = append(levelsList, map[string]interface{}{
			"id":   level.Id,
			"name": level.LevelName,
		})
		levelsMap[level.Id] = level.LevelName
	}

	tagDb := implement.NewUserTagDb(db.Db)
	tags, err2 := tagDb.UserTagAllByAsc()
	if err2 != nil {
		e.OutErr(c, e.ERR_DB_ORM, err2.Error())
		return
	}
	tagsList := make([]map[string]interface{}, 0)
	tagsMap := make(map[int]string)
	for _, tag := range tags {
		tagsList = append(tagsList, map[string]interface{}{
			"id":   tag.Id,
			"name": tag.TagName,
		})
		tagsMap[tag.Id] = tag.TagName
	}

	applies, total, err3 := svc.WithDrawManagementGetApply(db.Db, req)
	if err3 != nil {
		e.OutErr(c, e.ERR_DB_ORM, err3.Error())
		return
	}

	list := make([]md.GetWithdrawApplyListNode, len(*applies))
	parentIDs := make([]int64, len(*applies))
	UserIDs := make([]int64, len(*applies))
	for _, apply := range *applies {
		parentIDs = append(parentIDs, apply.ParentID)
		UserIDs = append(UserIDs, apply.UserID)
	}

	// 查询上级
	userDb := implement.NewUserDb(db.Db)
	parents, err := userDb.UserFindByParams(map[string]interface{}{
		"key":   "id",
		"value": parentIDs,
	})
	if err != nil {
		e.OutErr(c, e.ERR_DB_ORM, err.Error())
		return
	}
	parentsMap := make(map[int64]model.User)
	for _, parent := range parents {
		parentsMap[parent.Id] = parent
	}

	// 查询标签
	recordsDb := implement.NewUserTagRecordsDb(db.Db)
	records, err := recordsDb.UserTagRecordsFindByParams(map[string]interface{}{
		"key":   "uid",
		"value": UserIDs,
	})
	if err != nil {
		e.OutErr(c, e.ERR_DB_ORM, err.Error())
		return
	}
	recordsMap := make(map[int64][]md.TagNode)
	for _, record := range *records {
		temp := md.TagNode{
			TagID:   record.TagId,
			TagName: "",
		}
		tagName, ok := tagsMap[record.TagId]
		temp.TagName = tagName
		v, ok := recordsMap[record.Uid]
		if ok {
			v = append(v, temp)
		} else {
			recordsMap[record.Uid] = []md.TagNode{temp}
		}
	}

	for i, apply := range *applies {
		list[i] = md.GetWithdrawApplyListNode{
			WithdrawApplyId:  apply.WithdrawApplyId,
			UserID:           apply.UserID,
			Nickname:         apply.Nickname,
			ParentID:         apply.ParentID,
			AliPayName:       apply.AliPayName,
			WechatPayName:    apply.WxPayName,
			AliPayAccount:    apply.AliPayAccount,
			WechatPayAccount: apply.WxPayAccount,
			WithdrawType:     apply.WithdrawType,
			InviteCode:       apply.InviteCode,
			Amount:           apply.Amount,
			ActualReceipt:    apply.RealAmount,
			SysFee:           apply.SysFee,
			State:            apply.State,
			ApplyAt:          apply.ApplyAt,
			PayAt:            apply.PayAt,
			Memo:             apply.Memo,
		}
		if apply.Amount != "" && apply.SysFee != "" {
			actualReceipt := utils.StrToFloat64(apply.Amount) - utils.StrToFloat64(apply.SysFee)
			list[i].ActualReceipt = utils.Float64ToStr(actualReceipt)
		}
		if apply.ParentID != 0 {
			v, ok := parentsMap[apply.ParentID]
			if ok {
				list[i].ParentPhone = v.Phone
			}
		}
		tagList, ok := recordsMap[apply.UserID]
		if ok {
			list[i].Tag = tagList
		}
	}
	applyDb := implement.NewFinWithdrawApplyDb(db.Db)
	underReviewAmount, err := applyDb.FinWithdrawApplyAmountGetByParams(map[string]interface{}{
		"key":   "state",
		"value": 0,
	})
	if err != nil {
		e.OutErr(c, e.ERR_DB_ORM, err.Error())
		return
	}
	pendingAmount, err := applyDb.FinWithdrawApplyAmountGetByParams(map[string]interface{}{
		"key":   "state",
		"value": 4,
	})
	if err != nil {
		e.OutErr(c, e.ERR_DB_ORM, err.Error())
		return
	}
	paySucceedAmount, err := applyDb.FinWithdrawApplyAmountGetByParams(map[string]interface{}{
		"key":   "state",
		"value": 2,
	})
	if err != nil {
		e.OutErr(c, e.ERR_DB_ORM, err.Error())
		return
	}
	payFailedAmount, err := applyDb.FinWithdrawApplyAmountGetByParams(map[string]interface{}{
		"key":   "state",
		"value": 3,
	})
	if err != nil {
		e.OutErr(c, e.ERR_DB_ORM, err.Error())
		return
	}

	resp := md.GetWithdrawApplyListResp{
		ReasonList: []map[string]interface{}{
			{
				"value": enum.FinWithdrawApplyReasonForNotRule,
				"name":  enum.FinWithdrawApplyReasonForNotRule.String(),
			},
			{
				"value": enum.FinWithdrawApplyReasonForAccountAbnormal,
				"name":  enum.FinWithdrawApplyReasonForAccountAbnormal.String(),
			},
			{
				"value": enum.FinWithdrawApplyReasonForFundAbnormal,
				"name":  enum.FinWithdrawApplyReasonForFundAbnormal.String(),
			},
		},
		LevelsList:        levelsList,
		TagsList:          tagsList,
		PendingAmount:     utils.Float64ToStr(pendingAmount),
		PaySucceedAmount:  utils.Float64ToStr(paySucceedAmount),
		PayFailedAmount:   utils.Float64ToStr(payFailedAmount),
		UnderReviewAmount: utils.Float64ToStr(underReviewAmount),
		List:              list,
		Paginate: md.Paginate{
			Limit: req.Limit,
			Page:  req.Page,
			Total: total,
		},
	}
	e.OutSuc(c, resp, nil)
}

// WithdrawApplyAudit
// @Summary      财务中心-提现-审核
// @Tags         提现
// @Description  提现审核
// @Accept       json
// @Produce      json
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Param    req    body	md.WithdrawApplyAuditReq 	false  "筛选条件"
// @Success      200   {string}  	 "success"
// @Failure      400   {object}   md.Response              	"具体错误"
// @Router       /api/financialCenter/withdraw/audit [POST]
func WithdrawApplyAudit(c *gin.Context) {
	var req *md.WithdrawApplyAuditReq
	if err1 := c.ShouldBindJSON(&req); err1 != nil {
		e.OutErr(c, e.ERR_INVALID_ARGS, err1.Error())
		return
	}

	//1、查找对应提现申请单
	finWithdrawApplyDb := implement.NewFinWithdrawApplyDb(db.Db)
	finWithdrawApply, err := finWithdrawApplyDb.FinWithdrawApplyGet(req.WithdrawApplyId)
	if err != nil {
		e.OutErr(c, e.ERR_DB_ORM, err.Error())
		return
	}
	if finWithdrawApply == nil {
		e.OutErr(c, e.ERR_NOT_FAN, "提现记录不存在")
		return
	}

	//2、判断审核状态
	if req.AuditState == 1 {
		//通过(推mq、修改提现单成功)
		finWithdrawApply.State = int(enum.FinWithdrawApplyStateForIng)
		updateAffected, err1 := finWithdrawApplyDb.UpdateFinWithdrawApply(finWithdrawApply, "state")
		if err1 != nil {
			e.OutErr(c, e.ERR_DB_ORM, err1.Error())
			return
		}
		if updateAffected <= 0 {
			e.OutErr(c, e.ERR_DB_ORM, "更新提现单状态失败")
			return
		}

		ch, err1 := rabbit.Cfg.Pool.GetChannel()
		if err1 != nil {
			e.OutErr(c, e.ERR_INIT_RABBITMQ, err1.Error())
			return
		}
		defer ch.Release()
		var data md2.EggFinWithdrawApplyData
		err = copier.Copy(&data, &finWithdrawApply)
		if err != nil {
			e.OutErr(c, e.ERR, err.Error())
			return
		}

		ch.Publish(md2.EggAppExchange, utils.SerializeStr(data), md2.EggFinWithdrawApply)
	} else {
		//拒绝(退余额、修改提现单失败)
		session := db.Db.NewSession()
		defer session.Close()
		session.Begin()

		finWithdrawApply.State = int(enum.FinWithdrawApplyStateForBad)
		updateAffected, err1 := finWithdrawApplyDb.UpdateFinWithdrawApplyBySession(session, finWithdrawApply, "state")
		if err1 != nil {
			e.OutErr(c, e.ERR_DB_ORM, err1.Error())
			return
		}
		if updateAffected <= 0 {
			e.OutErr(c, e.ERR_DB_ORM, "更新提现单状态失败")
			return
		}

		dealUserWalletReq := md3.DealUserWalletReq{
			Direction: "sub",
			Kind:      int(enum.UserWithdrawBad),
			Title:     enum.UserWithdrawBad.String(),
			Uid:       finWithdrawApply.Uid,
			Amount:    utils.StrToFloat64(finWithdrawApply.Amount),
		}

		err = rule.DealUserWallet(session, dealUserWalletReq)
		if err != nil {
			session.Rollback()
			e.OutErr(c, e.ERR, err.Error())
			return
		}

		err = session.Commit()
		if err != nil {
			_ = session.Rollback()
			e.OutErr(c, e.ERR_DB_ORM, err)
			return
		}
	}

	e.OutSuc(c, "success", nil)
}