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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.json.JSONUtil;
import com.hzs.common.core.annotation.RepeatSubmitSimple;
import com.hzs.common.core.constant.MemberFieldConstants;
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.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.domain.member.account.CuMemberAccount;
import com.hzs.common.domain.member.account.CuMemberTransfer;
import com.hzs.common.domain.member.base.CuMember;
import com.hzs.common.domain.member.detail.CuMemberServiceLog;
import com.hzs.common.domain.member.detail.CuMemberServiceLogExt;
import com.hzs.common.domain.member.ext.CuMemberExt;
import com.hzs.common.domain.system.config.BdAccount;
import com.hzs.common.domain.system.config.BdTransfer;
import com.hzs.common.domain.system.config.BdTransferSpecial;
import com.hzs.common.security.utils.SecurityUtils;
import com.hzs.common.core.utils.TransactionUtils;
import com.hzs.member.account.dto.CuMemberRechargeAccountParam;
import com.hzs.member.account.dto.CuMemberTransferParam;
import com.hzs.member.account.service.*;
import com.hzs.member.account.vo.BdAccountVO;
import com.hzs.member.base.service.ICuMemberService;
import com.hzs.member.base.vo.UpPolicyCurrencyVO;
import com.hzs.member.detail.service.ICuMemberServiceLogService;
import com.hzs.system.base.dto.CurrencyDTO;
import com.hzs.system.config.IAccountServiceApi;
import com.hzs.system.config.IGradeServiceApi;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;

/**
 * 会员提现表 前端控制器
 */
@RestController
@RequestMapping("/api/transfer")
public class ApiCuMemberTransferController extends BaseController {

    @Autowired
    ICuMemberService cuMemberService;
    @Autowired
    ICuMemberTransferService cuMemberTransferService;
    @Autowired
    ICuMemberBaseService cuMemberBaseService;
    @Autowired
    ICuMemberAccountService cuMemberAccountService;
    @Autowired
    ICuMemberBaseService memberBaseService;
    @Autowired
    ICuMemberServiceLogService memberServiceLogService;

    @DubboReference
    IAccountServiceApi accountServiceApi;

    /**
     * 根据用户编号查询中文脱敏
     *
     * @return
     */
    @GetMapping("/chinese-name")
    public AjaxResult chineseDesensitization(String memberCode) {
        CuMember member = cuMemberService.getMemberByCode(memberCode);
        if (member != null) {
            String memberName = member.getMemberName();
            memberName = DesensitizedUtil.chineseName(memberName);
            return AjaxResult.success().put("memberName", memberName);
        } else {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.RECHAGER_USER_NOT_EXIST));
        }
    }

    /**
     * 查询可转账币种
     */
    @GetMapping("/transfer-account")
    public AjaxResult getAccount() {
        Integer pkCountry = SecurityUtils.getPkCountry();
        Long pkMember = SecurityUtils.getUserId();
        List<BdAccount> accountList = cuMemberBaseService.getAccountByCountry(EAccountProperty.IS_TRANSFER.getValue(), pkCountry);
        List<CuMemberServiceLog> logList = getServiceLogValue(pkCountry, pkMember);
        if (CollUtil.isNotEmpty(logList)) {
            UpPolicyCurrencyVO upPolicyCurrencyVO = JSONUtil.toBean(logList.get(0).getNewValue(), UpPolicyCurrencyVO.class);
            //政策币启用状态 0 已启用 1已禁用 EnableStatus
            Integer enableStatus = upPolicyCurrencyVO.getEnableStatus();
            //政策币转账状态 1允许 2禁止 EPopupType
            Integer transfer = upPolicyCurrencyVO.getTransfer();
            if (null != enableStatus && null != transfer) {
                if (enableStatus.equals(EnableStatus.ENABLE.getValue()) && transfer.equals(EPopupType.ALLOW.getValue())) {
                    BdAccount bdAccount = accountServiceApi.getBdAccountByFieldValue(pkCountry, EAccount.POLICY.getValue()).getData();
                    accountList.add(bdAccount);
                }
            }
        }
        return AjaxResult.success(BeanUtil.copyToList(accountList, BdAccountVO.class));
    }

    /**
     * 查询用户是否开通政策币
     *
     * @param pkCountry 国家ID
     * @param pkMember  会员ID
     * @return List<CuMemberServiceLog>
     */
    private List<CuMemberServiceLog> getServiceLogValue(Integer pkCountry, Long pkMember) {
        List<Integer> editTypeList = Collections.singletonList(EApprovalBusiness.POLICY_CURRENCY_YES_NO.getValue());
        CuMemberServiceLogExt log = new CuMemberServiceLogExt();
        log.setPkMember(pkMember);
        log.setPkCountry(pkCountry);
        log.setEditTypeList(editTypeList);
        return memberServiceLogService.selectServiceValue(log);
    }


    /**
     * 用户转账
     *
     * @param cuMemberTransferParam 转账入参
     * @return AjaxResult
     */
    @PostMapping("/add")
    @RepeatSubmitSimple
    public AjaxResult addTransferInfo(@RequestBody CuMemberTransferParam cuMemberTransferParam) {
        Integer pkCountry = SecurityUtils.getPkCountry();
        Long pkMember = SecurityUtils.getUserId();
        String memberCode = SecurityUtils.getMemberCode();

        CuMemberExt member = cuMemberService.getMemberByCode(memberCode);
        Assert.notNull(member, TransactionUtils.getContent(FinanceMsgConstants.TRANSFER_OUT_USER_NOT_EXIST));

        //币种ID
        Integer pkAccount = cuMemberTransferParam.getPkAccount();
        if (null == pkAccount) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.TRANSFER_OUT_ACCOUNT_NOT_EMPTY));
        }

        //校验支付密码
        String payPwd = member.getPayPwd();
        if (StringUtils.isEmpty(payPwd) || !SecurityUtils.matchesPassword(cuMemberTransferParam.getPayPwd(), payPwd)) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.PAYMENT_PASSWORD_ERROR));
        }

        BigDecimal transferMoney = cuMemberTransferParam.getTransferMoney();
        if (transferMoney.compareTo(BigDecimal.ZERO) <= 0) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.INCORRECT_TRANSFER_AMOUNT));
        }

        //配置信息
        BdTransfer bdTransfer = cuMemberTransferService.getBdTransfer(pkCountry);
        if (null == bdTransfer) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.CONFIGURE_TRANSFER_CONFIGURATION));
        }
        //取整
        transferMoney = computeRounding(bdTransfer, transferMoney);

        BigDecimal minAmount = bdTransfer.getMinAmount();
        BigDecimal maxAmount = bdTransfer.getMaxAmount();
        if (transferMoney.compareTo(minAmount) < 0) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.CANNOT_LOWER_THAN_MINIMUM_TRANSFER_AMOUNT));
        }
        if (transferMoney.compareTo(maxAmount) > 0) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.CANNOT_GREATER_MAXIMUM_TRANSFER_AMOUNT));
        }
        //倍数
        Integer multiple = bdTransfer.getMultiple();
        //取余
        BigDecimal[] multiples = transferMoney.divideAndRemainder(new BigDecimal(multiple));
        if (multiples[1].compareTo(BigDecimal.ZERO) != 0) {
            return AjaxResult.error("转账金额不是" + multiple + "倍数");
        }

        //查询账户信息
        CuMemberAccount cuMemberAccount = cuMemberAccountService.queryCuMemberAccountByPkMember(pkMember);
        //是否转账
        Integer isTransfer = cuMemberAccount.getIsTransfer();
        //是否允许转账
        if (isTransfer.equals(EYesNo.NO.getIntValue())) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.NOT_ALLOWED_TRANSFER));
        }

        //接收方
        String toMemberCode = cuMemberTransferParam.getToMemberCode();
        CuMember toMember = cuMemberService.getMemberByCode(toMemberCode);
        Assert.notNull(toMember, TransactionUtils.getContent(FinanceMsgConstants.TRANSFER_IN_USER_NOT_EXIST));
        Long toPkMember = toMember.getPkId();
        //禁止登录的用户无法接受转账
        if (toMember.getAccountStatus().equals(EAccountStatus.SHUT_DOWN.getValue())) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.TRANSFER_IN_USER_NOT_ALLOWED));
        }
        //非洲、欧洲奖金账户可以自己转自己
        BdAccount bdAccount = accountServiceApi.getAccount(pkAccount).getData();
        if (EAccount.BONUS.getValue() != bdAccount.getFieldValue() && pkMember.equals(toPkMember)) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.NOT_TRANSFER_MONEY_TO_YOURSELF));
        }

        if (!member.getPkSettleCountry().equals(toMember.getPkSettleCountry())) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.NOT_ALLOWED_CROSS_BORDER_TRANSFER));
        }

        //个人转账状态（0正常、1:全网）
        Integer transferStatus = cuMemberAccount.getTransferStatus();
        //血缘线配置 是否血缘(0是 1 否)
        Integer reference = bdTransfer.getIsReference();
        //走血缘
        if (isReference(transferStatus, reference, pkMember, toPkMember)) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.RECEIVER_NUMBER_NOT_IN_BLOOD_LINE));
        }

        //币种value值
        Integer pkAccountValue = memberBaseService.getAccountValueById(pkAccount);
        //查询余额
        BigDecimal balance = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.ACCOUNT + pkAccountValue);
        BigDecimal lockAccount = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.LOCK_TRANSFER_ACCOUNT + pkAccountValue);
        if (null != lockAccount && lockAccount.compareTo(BigDecimal.ZERO) > 0) {
            balance = balance.subtract(lockAccount);
        }

        //余额不足
        if (balance.compareTo(transferMoney) < 0) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.BALANCE_NOT_ENOUGH));
        }
        //手续费金额
        BigDecimal serviceRatio = this.computeServiceCharge(bdTransfer, transferMoney);
        //可用金额
        BigDecimal issuedAmount = transferMoney.subtract(serviceRatio);

        //单号
        String code = CommonUtil.createSerialNumber(EOrderPrefix.TRANSFER_CODE.getValue());
        //汇率
        CurrencyDTO currencyDTO = memberBaseService.getCurrency(pkCountry);
        //转入币种ID（从配置中获取）
        Integer toPkAccount = accountServiceApi.getPkAccount(pkAccount).getData();

        CuMemberTransfer cuMemberTransfer = CuMemberTransfer.builder().pkMember(pkMember)
                .pkAccount(pkAccount).transferCode(code).toPkMember(toPkMember)
                .pkToAccount(toPkAccount).pkRate(currencyDTO.getPkId())
                .transferMoney(transferMoney).remarks(cuMemberTransferParam.getRemarks())
                .serviceCharge(serviceRatio).issuedAmount(issuedAmount)
                .build();
        cuMemberTransfer.setPkCountry(pkCountry);
        cuMemberTransfer.setPkCreator(pkMember);
        CuMemberAccount toMemberAccount = cuMemberAccountService.queryCuMemberAccountByPkMember(cuMemberTransfer.getToPkMember());
        return toAjax(cuMemberTransferService.saveMemberTransferInfo(cuMemberTransfer, cuMemberAccount, toMemberAccount));

    }

    /**
     * 判断是否走血缘
     *
     * @param transferStatus 个人转账状态（0正常、1:全网）
     * @param reference      血缘线配置 是否血缘(0是 1 否)
     * @param pkMember       转出方
     * @param toPkMember     转入方
     * @return Boolean
     */
    private Boolean isReference(Integer transferStatus, Integer reference, Long pkMember, Long toPkMember) {
        return (reference.equals(EYesNo.YES.getIntValue()) || transferStatus.equals(EYesNo.YES.getIntValue())) && !cuMemberTransferService.isBloodLine(pkMember, toPkMember);
    }

    /**
     * 转账的特殊配置
     *
     * @param pkMember      转出方ID
     * @param transferMoney 转账金额
     * @param toPkMember    转入方ID
     * @return AjaxResult
     */
    private AjaxResult transferSpecial(BdTransferSpecial transferSpecial, Long pkMember, BigDecimal transferMoney, Long toPkMember) {
        //特殊配置
        if (null != transferSpecial) {
            //某个人的最低提现金额
            BigDecimal minAmountMoney = transferSpecial.getMinAmountMoney();
            if (transferMoney.compareTo(minAmountMoney) < 0) {
                return AjaxResult.error("转账金额不能低于最低转账金额");
            }
            Integer specialConfig = transferSpecial.getSpecialConfig();
            //不校验
            if (specialConfig.equals(ETransferSpecial.NO_CONTROL.getValue())) {
                return AjaxResult.success();
            }
            //推荐
            if (specialConfig.equals(ETransferSpecial.BLOOD_ALL.getValue()) && !cuMemberTransferService.isBloodLine(pkMember, toPkMember)) {
                return AjaxResult.error("接收方编号不在血缘线中");
            }
            if (specialConfig.equals(ETransferSpecial.BLOOD_ON_UMBRELLA.getValue()) && !cuMemberTransferService.isBloodKinshipOnUmbrella(pkMember, toPkMember)) {
                return AjaxResult.error("接收方编号不在血缘伞上");
            }
            if (specialConfig.equals(ETransferSpecial.BLOOD_UNDER_UMBRELLA.getValue()) && !cuMemberTransferService.isBloodKinshipUnderUmbrella(pkMember, toPkMember)) {
                return AjaxResult.error("接收方编号不在血缘伞下");
            }
            //安置
            if (specialConfig.equals(ETransferSpecial.PLACE_ALL.getValue()) && !cuMemberTransferService.isPlaceSponsorOnline(pkMember, toPkMember)) {
                return AjaxResult.error("接收方编号不在安置线中");
            }
            if (specialConfig.equals(ETransferSpecial.PLACE_ON_UMBRELLA.getValue()) && !cuMemberTransferService.isPlaceSponsorOnUmbrella(pkMember, toPkMember)) {
                return AjaxResult.error("接收方编号不在安置伞上");
            }
            if (specialConfig.equals(ETransferSpecial.PLACE_UNDER_UMBRELLA.getValue()) && !cuMemberTransferService.isPlaceSponsorUnderUmbrella(pkMember, toPkMember)) {
                return AjaxResult.error("接收方编号不在安置伞下");
            }
        }
        return AjaxResult.success();
    }

    /**
     * 计算手续费金额
     *
     * @param bdTransfer    转账配置
     * @param transferMoney 转账金额
     * @return BigDecimal
     */
    private BigDecimal computeServiceCharge(BdTransfer bdTransfer, BigDecimal transferMoney) {
        //手续费类型
        Integer serviceType = bdTransfer.getServiceType();
        BigDecimal serviceRatio = bdTransfer.getServiceRatio();
        //按金额
        if (serviceType.equals(ECalType.VALUE.getValue())) {
            return serviceRatio;
        } else {//按比例
            //转化为百分比比率
            BigDecimal serviceChargeeRatio = serviceRatio.divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP);
            //手续费金额 = 本次提现金额 * 手续费比例
            return transferMoney.multiply(serviceChargeeRatio).setScale(2, BigDecimal.ROUND_HALF_UP);
        }
    }

    /**
     * 取整
     *
     * @param bdTransfer    转账配置
     * @param transferMoney 转账金额
     * @return BigDecimal
     */
    private BigDecimal computeRounding(BdTransfer bdTransfer, BigDecimal transferMoney) {
        BigDecimal roundIngAmount = BigDecimal.ZERO;
        Integer isRounding = bdTransfer.getIsRounding();
        if (isRounding.equals(EYesNo.YES.getIntValue())) {
            //向下取整
            roundIngAmount = transferMoney.setScale(0, BigDecimal.ROUND_DOWN);
        }
        return roundIngAmount;
    }

    /**
     * 查询用户余额
     *
     * @param pkAccount 币种ID
     * @return
     */
    @GetMapping("/member-balance")
    public AjaxResult findMemberBalance(Integer pkAccount) {
        Long pkMember = SecurityUtils.getUserId();
        CuMemberRechargeAccountParam cuMemberBalance = cuMemberAccountService.findMemberBalanceById(cuMemberBaseService.getAccountValueById(pkAccount), pkMember);
        return AjaxResult.success(cuMemberBalance.getAvailableBalance());
    }


}
