package com.hzs.member.account.controller.api;


import com.hzs.common.core.annotation.ColumnAuthority;
import com.hzs.common.core.annotation.RepeatSubmitSimple;
import com.hzs.common.core.constant.MagicNumberConstants;
import com.hzs.common.core.constant.MemberFieldConstants;
import com.hzs.common.core.constant.msg.CommonMsgConstants;
import com.hzs.common.core.constant.msg.FinanceMsgConstants;

import com.hzs.common.core.enums.*;
import com.hzs.common.core.utils.CommonUtil;
import com.hzs.common.core.utils.ComputeUtil;
import com.hzs.common.core.utils.StringUtils;
import com.hzs.common.core.utils.reflect.ReflectUtils;
import com.hzs.common.core.web.controller.BaseController;
import com.hzs.common.core.web.domain.AjaxResult;
import com.hzs.common.core.web.page.TableDataInfo;
import com.hzs.common.domain.member.account.CuMemberAccount;
import com.hzs.common.domain.member.account.CuMemberRechargeExt;
import com.hzs.common.domain.member.base.CuMember;

import com.hzs.common.domain.member.ext.CuMemberAccountExt;
import com.hzs.common.domain.member.ext.CuMemberExt;
import com.hzs.common.domain.sale.ext.BdWaresInfoExt;
import com.hzs.common.security.utils.SecurityUtils;
import com.hzs.common.core.utils.TransactionUtils;
import com.hzs.member.account.dto.CuMemberRedeemPointsParam;
import com.hzs.member.account.service.ICuMemberAccountService;
import com.hzs.member.account.service.ICuMemberBaseService;
import com.hzs.member.account.service.ICuMemberRechargeApplicationService;
import com.hzs.member.account.service.ICuMemberRechargeService;
import com.hzs.member.account.vo.CuMemberRechargeApplicationVO;
import com.hzs.member.account.vo.CuMemberRechargeVO;
import com.hzs.member.account.vo.CuMemberRedeemPointsVO;
import com.hzs.member.base.service.ICuMemberService;
import com.hzs.sale.wares.IWaresServiceApi;
import com.hzs.system.base.dto.CurrencyDTO;
import com.hzs.system.config.IAreaCurrencyServiceApi;
import com.hzs.system.config.dto.AreaCurrencyDTO;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;

import java.util.List;


/**
 * <p>
 * 会员充值表 前端控制器
 * </p>
 *
 * @author hzs
 * @since 2022-09-08
 */

@RestController
@RequestMapping("/api/recharge")
public class ApiCuMemberRechargeController extends BaseController {

    @Autowired
    ICuMemberRechargeService cuMemberRechargeService;

    @Autowired
    ICuMemberService cuMemberService;

    @Autowired
    ICuMemberBaseService cuMemberBaseService;

    @Autowired
    ICuMemberAccountService cuMemberAccountService;

    @Autowired
    ICuMemberRechargeApplicationService cuMemberRechargeApplicationService;

    @DubboReference
    IAreaCurrencyServiceApi areaCurrencyServiceApi;


    @DubboReference
    IWaresServiceApi waresServiceApi;

    /**
     * 会员端充值前调用接口（预充值）
     *
     * @return AjaxResult
     * @rechargeAmount 充值金额
     * @memberCode 会员编号
     */
    @GetMapping("/preCharge")
    public AjaxResult precharge(String rechargeAmount, @RequestParam(required = false) String memberCode) {
        AjaxResult ajaxResult = new AjaxResult();
        if (StringUtils.isEmpty(rechargeAmount)) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.RECHAGER_AMOUNT_NOT_EMPTY));
        }
        if (new BigDecimal(rechargeAmount).compareTo(BigDecimal.ZERO) < 0) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.RECHARGE_AMOUNT_NOT_NEGATIVE));
        }
        Integer pkCountry = SecurityUtils.getPkCountry();
        Long pkMember = SecurityUtils.getUserId();
        //为其它人充值
        if (StringUtils.isNotEmpty(memberCode)) {
            CuMember member = cuMemberService.getMember(memberCode);
            if (null == member) {
                return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.RECHAGER_USER_NOT_EXIST));
            }
            pkMember = member.getPkId();
        }
        //充值单号
        String rechargeCode = CommonUtil.createSerialNumber(EOrderPrefix.RECHARGE_CODE.getValue());
        boolean result = cuMemberRechargeService.preCharge(rechargeAmount, pkCountry, pkMember, rechargeCode);
        if (result) {
            ajaxResult.put("flag", "1");
            ajaxResult.put("orderCode", rechargeCode);

        } else {
            ajaxResult.put("flag", "2");
            ajaxResult.put("msg", TransactionUtils.getContent(FinanceMsgConstants.RECHAGER_FAIL));
        }
        return ajaxResult;
    }

    /**
     * 校验用户支付密码是否正确
     *
     * @param pwd
     * @return AjaxResult
     */
    @GetMapping("/check-pwd")
    public AjaxResult checkPwd(String pwd) {
        if (StringUtils.isEmpty(pwd)) {
            // 用户支付密不能为空
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.PAYMENT_PASSWORD_NOT_EMPTY));
        }
        CuMember cuMember = cuMemberService.queryMember(SecurityUtils.getUserId());
        if (SecurityUtils.matchesPassword(pwd, cuMember.getPayPwd())) {
            return AjaxResult.success();
        }
        return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.PAYMENT_PASSWORD_ERROR));
    }


    /**
     * 显示复消积分的默认值
     *
     * @return AjaxResult
     */
    @GetMapping("/show-recoil")
    public AjaxResult showRecoil() {
        Integer pkCountry = SecurityUtils.getPkCountry();
        CurrencyDTO currency = cuMemberBaseService.getCurrency(pkCountry);

        //查询复消专区的商品信息
        BdWaresInfoExt bdWaresInfo = waresServiceApi.selectWaresBySpecial(ESpecialArea.RESALE_INTEGRAL_AREA.getValue(), pkCountry).getData();
        BigDecimal price = bdWaresInfo.getPrice();

        CuMemberRedeemPointsVO redeemPointsVO = CuMemberRedeemPointsVO.builder()
                .redeemPoints(price)
                .redeemIncome(MagicNumberConstants.POINT_CAPPING.multiply(currency.getInExchangeRate()))
                .payAmount(price)
                .build();
        return AjaxResult.success(redeemPointsVO);
    }

    /**
     * 兑换复消积分
     *
     * @param webParam 参数
     * @return AjaxResult
     */
    @PostMapping("/redeem-points")
    @RepeatSubmitSimple
    public AjaxResult redeemPoints(@RequestBody CuMemberRedeemPointsParam webParam) {
        Integer pkCountry = SecurityUtils.getPkCountry();
        Long pkMember = SecurityUtils.getUserId();

        Integer times = webParam.getTimes();
        if (null == times) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.REDEMPTION_TIMES_CANNOT_EMPTY));
        }
        CuMember cuMember = cuMemberService.queryMember(pkMember);
        String payPwd = webParam.getPayPwd();

        //校验支付密码
        if (StringUtils.isEmpty(payPwd)) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.PAYMENT_PASSWORD_ERROR));
        }

        if (!SecurityUtils.matchesPassword(payPwd, cuMember.getPayPwd())) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.PAYMENT_PASSWORD_ERROR));
        }

        //查询复消专区的商品信息
        BdWaresInfoExt bdWaresInfo = waresServiceApi.selectWaresBySpecial(ESpecialArea.RESALE_INTEGRAL_AREA.getValue(), pkCountry).getData();
        BigDecimal price = bdWaresInfo.getPrice();
        if (price.compareTo(BigDecimal.ZERO) <= 0) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.PRODUCTS_PRICE_CANNOT_ZERO));
        }
        //兑换的金额
        BigDecimal redeemAmount = price.multiply(new BigDecimal(times.toString()));
        //查询兑换复消扣款配置
        List<AreaCurrencyDTO> areaCurrencyList = areaCurrencyServiceApi.queryAreaCurrencyByCondition(ESpecialArea.RESALE_INTEGRAL_AREA.getValue(), pkCountry).getData();
        //查询会员账户信息
        CuMemberAccount cuMemberAccount = CuMemberAccount.builder().pkMember(pkMember).build();
        cuMemberAccount.setPkCountry(pkCountry);
        List<CuMemberAccountExt> cuMemberAccountExtList = cuMemberAccountService.queryMemberAccountByCondition(cuMemberAccount);
        //根据配置扣减兑换币种
        CuMemberRedeemPointsParam param = CuMemberRedeemPointsParam.builder().pkMember(pkMember).pkCountry(pkCountry)
                .times(times).bdWaresInfo(bdWaresInfo).redeemAmount(redeemAmount)
                .cuMemberAccountExt(cuMemberAccountExtList.get(0))
                .build();
        cuMemberRechargeService.handleReDeemAmount(cuMemberAccountExtList.get(0), redeemAmount, areaCurrencyList, param);
        if (!param.getIsPayment()) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.BALANCE_NOT_ENOUGH));
        }
        return toAjax(cuMemberRechargeService.redeemPoints(param));
    }


    /**
     * 扣减金额显示
     *
     * @param times 次数
     * @return AjaxResult
     */
    @GetMapping("/deduction-amount")
    public AjaxResult deductionAmount(Integer times) {
        Integer pkCountry = SecurityUtils.getPkCountry();
        Long pkMember = SecurityUtils.getUserId();
        if (null == times) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.REDEMPTION_TIMES_CANNOT_EMPTY));
        }
        //查询复消专区的商品信息
        BdWaresInfoExt bdWaresInfo = waresServiceApi.selectWaresBySpecial(ESpecialArea.RESALE_INTEGRAL_AREA.getValue(), pkCountry).getData();
        BigDecimal price = bdWaresInfo.getPrice();
        if (price.compareTo(BigDecimal.ZERO) <= 0) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.PRODUCTS_PRICE_CANNOT_ZERO));
        }
        //兑换的金额
        BigDecimal redeemAmount = price.multiply(new BigDecimal(times.toString()));
        //查询兑换复消扣款配置
        List<AreaCurrencyDTO> areaCurrencyList = areaCurrencyServiceApi.queryAreaCurrencyByCondition(ESpecialArea.RESALE_INTEGRAL_AREA.getValue(), pkCountry).getData();
        //查询会员账户信息
        CuMemberAccount cuMemberAccount = CuMemberAccount.builder().pkMember(pkMember).build();
        cuMemberAccount.setPkCountry(pkCountry);
        List<CuMemberAccountExt> cuMemberAccountExtList = cuMemberAccountService.queryMemberAccountByCondition(cuMemberAccount);
        CuMemberAccountExt memberAccount = cuMemberAccountExtList.get(0);
        memberAccount.setPayPwd(null);

        handleSaOrderAmount(memberAccount, redeemAmount, BigDecimal.ZERO, areaCurrencyList);
        return AjaxResult.success(memberAccount);
    }


    private Boolean handleSaOrderAmount(CuMemberAccountExt cuMemberAccount, BigDecimal payMoney, BigDecimal postage, List<AreaCurrencyDTO> areaCurrencyDTOList) {
        boolean flag = Boolean.TRUE;
        if (!ComputeUtil.compareValue(ComputeUtil.computeAdd(payMoney, postage))) {
            return Boolean.TRUE;
        }
        cuMemberAccount.setIsPayment(Boolean.FALSE);
        BigDecimal original = payMoney;
        for (AreaCurrencyDTO areaCurrencyDTO : areaCurrencyDTOList) {
            // 开始扣款
            // 待支付金额>0进行扣减
            if (ComputeUtil.compareValue(payMoney)) {
                // 获得特殊处理
                // 判断比例是否 > 0, 为强制扣除金额 ，强制扣除金额不满足，直接支付失败
                if (!ComputeUtil.compareValue(areaCurrencyDTO.getDeductRatio())) {
                    payMoney = subtract(payMoney, cuMemberAccount, areaCurrencyDTO.getFieldValue());
                } else {
                    BigDecimal minPayMoney = ComputeUtil.computeDivide(original.multiply(areaCurrencyDTO.getDeductRatio()), BigDecimal.valueOf(100));
                    BigDecimal originalPayMoney = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.PAY_ACCOUNT + areaCurrencyDTO.getFieldValue());
                    if (originalPayMoney == null) {
                        originalPayMoney = BigDecimal.ZERO;
                    }
                    ReflectUtils.invokeSetter(cuMemberAccount, MemberFieldConstants.PAY_ACCOUNT + areaCurrencyDTO.getFieldValue(), ComputeUtil.computeAdd(originalPayMoney, minPayMoney));
                    payMoney = payMoney.subtract(minPayMoney);
                }
            }
            // 对邮费进行单独处理 邮费>0 进行扣减
            if (areaCurrencyDTO.getIsPostage() != null && areaCurrencyDTO.getIsPostage() == EYesNo.YES.getIntValue() && postage.compareTo(BigDecimal.ZERO) > 0) {
                postage = subtract(postage, cuMemberAccount, areaCurrencyDTO.getFieldValue());
            }
            // 每次扣除后判断是否扣除完毕，扣除完毕结束
            if (flag && payMoney.compareTo(BigDecimal.ZERO) == 0 && postage.compareTo(BigDecimal.ZERO) == 0) {
                cuMemberAccount.setIsPayment(Boolean.TRUE);
                break;
            }
        }
        return flag;
    }


    /**
     * 订单支付按币种扣款
     *
     * @param payMoney        待支付金额
     * @param cuMemberAccount 会员账户
     * @param key             账户key值
     */
    BigDecimal subtract(BigDecimal payMoney, CuMemberAccountExt cuMemberAccount, Integer key) {
        if (payMoney.compareTo(BigDecimal.ZERO) > 0) {
            BigDecimal accountValue = getAccountByKey(cuMemberAccount, key);
            if (!ComputeUtil.compareValue(accountValue)) {
                return payMoney;
            }
            BigDecimal value = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.PAY_ACCOUNT + key);
            if (value == null) {
                value = BigDecimal.ZERO;
            }
            if (payMoney.compareTo(accountValue) > 0) {
                value = value.add(accountValue);
                payMoney = payMoney.subtract(accountValue);
            } else {
                value = value.add(payMoney);
                payMoney = payMoney.subtract(payMoney);
            }
            ReflectUtils.invokeSetter(cuMemberAccount, MemberFieldConstants.PAY_ACCOUNT + key, value);
        }
        return payMoney;
    }


    /**
     * 通过反射获取账户余额
     *
     * @param cuMemberAccount 账户
     * @param key             键
     * @return 余额
     */
    BigDecimal getAccountByKey(CuMemberAccountExt cuMemberAccount, Integer key) {
        BigDecimal accountValue = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.ACCOUNT + key);
        BigDecimal lockAccountValue = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.LOCK_ACCOUNT + key);
        BigDecimal payAccountValue = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.PAY_ACCOUNT + key);
        if (null != lockAccountValue) {
            accountValue = accountValue.add(lockAccountValue.negate());
        }
        if (payAccountValue != null && ComputeUtil.compareValue(accountValue, payAccountValue)) {
            accountValue = accountValue.subtract(payAccountValue);
        }
        return accountValue;
    }


    /**
     * 保存会员申请
     *
     * @param rechargeApplicationVO
     * @return
     */
    @PostMapping("/save-application")
    @RepeatSubmitSimple
    public AjaxResult saveApplication(@RequestBody CuMemberRechargeApplicationVO rechargeApplicationVO) {
        String memberCode = rechargeApplicationVO.getMemberCode();
        if (StringUtils.isEmpty(memberCode) || StringUtils.isEmpty(rechargeApplicationVO.getRemitter())
                || null == rechargeApplicationVO.getRemittanceAmount() || null == rechargeApplicationVO.getRemittanceDate()
                || StringUtils.isEmpty(rechargeApplicationVO.getRemittanceInstructions())) {
            // 缺少参数
            return AjaxResult.error(TransactionUtils.getContent(CommonMsgConstants.MISSING_PARAM));
        }
        Integer pkCountry = SecurityUtils.getPkCountry();
        CuMemberExt member = cuMemberService.getMemberByCode(memberCode);
        if (null == member) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.MEMBER_NOT_ERROR));
        }
        Integer pkSettleCountry = member.getPkSettleCountry();
        //不能跨国转账
        if (!pkSettleCountry.equals(pkCountry)) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.RECHAGER_NOT_CROSS_COUNTRY));
        }
        rechargeApplicationVO.setPkMember(member.getPkId());
        rechargeApplicationVO.setPkCountry(pkCountry);
        rechargeApplicationVO.setPkCreator(SecurityUtils.getUserId());
        return toAjax(cuMemberRechargeApplicationService.saveApplication(rechargeApplicationVO));
    }

    @PostMapping("/list")
    public TableDataInfo findRechargeApplicationList(@RequestBody CuMemberRechargeApplicationVO rechargeApplicationVO) {
        rechargeApplicationVO.setPkCountry(SecurityUtils.getPkCountry());
        rechargeApplicationVO.setPkMember(SecurityUtils.getUserId());
        startPage();
        Object[] objects = cuMemberRechargeApplicationService.findRechargeApplicationList(rechargeApplicationVO);
        TableDataInfo tableDataInfo = getDataTable((List<CuMemberRechargeExt>) objects[0]);
        tableDataInfo.setRows((List<CuMemberRechargeApplicationVO>) objects[1]);
        return tableDataInfo;
    }

}
