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

import cn.hutool.core.collection.CollUtil;
import com.alibaba.nacos.shaded.org.checkerframework.checker.units.qual.A;
import com.hzs.common.core.annotation.RepeatSubmitSimple;
import com.hzs.common.core.constant.CountryConstants;
import com.hzs.common.core.constant.MagicNumberConstants;
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.core.web.page.TableDataInfo;
import com.hzs.common.domain.member.account.CuMemberAccount;
import com.hzs.common.domain.member.account.CuMemberWithdraw;
import com.hzs.common.domain.member.account.CuMemberWithdrawExt;
import com.hzs.common.domain.member.ext.CuMemberExt;
import com.hzs.common.domain.system.config.BdWithdrawal;
import com.hzs.common.security.utils.SecurityUtils;
import com.hzs.common.core.utils.TransactionUtils;
import com.hzs.member.account.dto.CuMemberWithdrawParam;
import com.hzs.member.account.service.ICuMemberAccountService;
import com.hzs.member.account.service.ICuMemberBankService;
import com.hzs.member.account.service.ICuMemberBaseService;
import com.hzs.member.account.service.ICuMemberWithdrawService;
import com.hzs.member.account.vo.CuMemberBankVO;
import com.hzs.member.account.vo.CuMemberWithdrawVO;
import com.hzs.member.account.vo.CuMemberWithdrawalAddVO;
import com.hzs.member.base.service.ICuMemberService;
import com.hzs.system.base.dto.CurrencyDTO;
import com.hzs.system.config.IGradeServiceApi;
import com.hzs.system.config.IWithdrawalServiceApi;
import lombok.extern.slf4j.Slf4j;
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.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;

/**
 * 会员提现表 前端控制器
 *
 * @author hzs
 * @since 2022-09-06
 */
@Slf4j
@RestController
@RequestMapping("/api/withdraw")
public class ApiCuMemberWithdrawController extends BaseController {

    @Autowired
    ICuMemberBankService cuMemberBankService;

    @Autowired
    ICuMemberService cuMemberService;

    @DubboReference
    IWithdrawalServiceApi withdrawalServiceApi;

    @Autowired
    ICuMemberBaseService baseService;

    @Autowired
    ICuMemberAccountService cuMemberAccountService;

    @Autowired
    ICuMemberWithdrawService cuMemberWithdrawService;


    @DubboReference
    IGradeServiceApi gradeServiceApi;

    /**
     * 提现时展示信息
     *
     * @return AjaxResult
     */
    @GetMapping("/show/add")
    public AjaxResult showAddWithdrawInfo(Integer pkAccount, BigDecimal cashAmount) {
        Integer pkCountry = SecurityUtils.getPkCountry();
        Long pkMember = SecurityUtils.getUserId();
        if (null == pkAccount) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.SELECT_WITHDRAWAL_ACCOUNT));
        }
        if (null == cashAmount) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.ENTER_WITHDRAWAL_AMOUNT));
        }
        //提现配置信息
        BdWithdrawal bdWithdrawal = withdrawalServiceApi.queryWithdrawal(pkCountry).getData();
        if (null == bdWithdrawal) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.CONFIGURE_WITHDRAWAL_INFO));
        }
        CuMemberAccount cuMemberAccount = cuMemberAccountService.queryCuMemberAccountByPkMember(pkMember);
        Integer accountValue = baseService.getAccountValueById(pkAccount);
        //余额
        BigDecimal balance = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.ACCOUNT + accountValue);
        //可用金额
        BigDecimal availableBalance = getAvailableBalance(accountValue, cuMemberAccount);
        //手续费金额
        BigDecimal serviceChargeAmount = cuMemberWithdrawService.computeServiceCharge(pkCountry, cashAmount);

        CuMemberWithdrawalAddVO cuMemberWithdrawalAddVO = CuMemberWithdrawalAddVO.builder()
                .minAmount(bdWithdrawal.getMinAmount()).maxAmount(bdWithdrawal.getMaxAmount())
                .amount(availableBalance).balance(balance).srviceCharge(serviceChargeAmount).build();
        return AjaxResult.success(cuMemberWithdrawalAddVO);
    }

    /**
     * 用户提现
     * 提现时先扣账户的钱，撤销时返回账户的钱
     *
     * @param cuMemberWithdrawParam 提现入参
     * @return AjaxResult
     */
    @PostMapping("/add")
    @RepeatSubmitSimple
    public AjaxResult addWithdrawInfo(@RequestBody CuMemberWithdrawParam cuMemberWithdrawParam) {
        Integer pkCountry = SecurityUtils.getPkCountry();
        Long pkMember = SecurityUtils.getUserId();
        String memberCode = SecurityUtils.getMemberCode();

        //是否可提现（周-、周二可提现）
        if (isWithdraw().equals(EYesNo.NO.getIntValue())) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.WITHDRAW_CYCLE));
        }

        CuMemberExt cuMemberLoginExt = cuMemberService.getMemberByCode(memberCode);
        if (null == cuMemberLoginExt) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.RECHAGER_USER_NOT_EXIST));
        }
        //获取银行卡信息
        Long pkBank = cuMemberWithdrawParam.getPkBank();
        CuMemberBankVO memberBank = cuMemberBankService.selectCuMemberBankById(pkBank);
        if (null == memberBank) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.BIND_BANK_CARD));
        }
        //校验支付密码
        String payPwd = cuMemberLoginExt.getPayPwd();
        if (StringUtils.isEmpty(payPwd) || !SecurityUtils.matchesPassword(cuMemberWithdrawParam.getPayPwd(), payPwd)) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.PAYMENT_PASSWORD_ERROR));
        }

        //查询提现账户
        Integer pkAccount = cuMemberWithdrawParam.getPkAccount();
        if (null == pkAccount) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.SELECT_WITHDRAWAL_ACCOUNT));
        }
        Integer accountsType = baseService.getAccountValueById(pkAccount);

        //查询账户信息
        CuMemberAccount cuMemberAccount = cuMemberAccountService.queryCuMemberAccountByPkMember(pkMember);
        //是否可提现
        Integer isWithdraw = cuMemberAccount.getIsWithdraw();
        //不允许提现
        if (isWithdraw.equals(EYesNo.NO.getIntValue())) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.NOT_ALLOWED_WITHDRAWAL));
        }
        //提现配置信息
        BdWithdrawal bdWithdrawal = withdrawalServiceApi.queryWithdrawal(pkCountry).getData();
        //提现次数
        Integer withdrawalNumber = bdWithdrawal.getWithdrawalNumber();
        // 只能发起配置项次数待审核提现 必须通过或者驳回之后才能发起下一笔
        List<CuMemberWithdraw> memberWithdraws = cuMemberWithdrawService.getWithdrawTimes(pkMember);
        if (CollUtil.isNotEmpty(memberWithdraws) && memberWithdraws.size() >= withdrawalNumber) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.EXCEEDING_WITHDRAWALS_NUMBER));
        }
        //提现金额校验
        BigDecimal minAmount = bdWithdrawal.getMinAmount();
        BigDecimal maxAmount = bdWithdrawal.getMaxAmount();
        if (null == minAmount || null == maxAmount) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.CONFIGURE_WITHDRAWAL_AMOUNT_LIMIT));
        }
        BigDecimal cashAmount = cuMemberWithdrawParam.getCashAmount();
        if (null == cashAmount) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.ENTER_WITHDRAWAL_AMOUNT));
        }
        //提现金额是否输入整数值
        Integer isRounding = bdWithdrawal.getIsRounding();
        if (isRounding.equals(EYesNo.YES.getIntValue()) && Boolean.TRUE.equals(!isIntegerValue(cashAmount))) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.ENTER_INTEGER_VALUE));
        }

        if (null != cashAmount && cashAmount.compareTo(minAmount) < 0) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.WITHDRAWAL_AMOUNT_GREATER_MINIMUM_AMOUNT));
        }
        if (null != cashAmount && cashAmount.compareTo(maxAmount) > 0) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.WITHDRAWAL_AMOUNT_LESS_MAXIMUM_AMOUNT));
        }
        //校验倍数
        if (pkCountry.equals(CountryConstants.CHINA_COUNTRY) && !remainder(cashAmount)) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.WITHDRAW_AMOUNT_MULTIPLE));
        }

        BigDecimal balance = getAvailableBalance(accountsType, cuMemberAccount);
        //余额不足
        if (balance.compareTo(cashAmount) < 0) {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.BALANCE_NOT_ENOUGH));
        }
        //本次应缴个税
        BigDecimal payIncomeTax = cuMemberWithdrawService.computeIncomeTaxValue(pkMember, cashAmount, pkCountry, minAmount);
        //手续费金额
        BigDecimal serviceChargeAmount = cuMemberWithdrawService.computeServiceCharge(pkCountry, cashAmount);
        BigDecimal issuedAmount = cashAmount.subtract(payIncomeTax).subtract(serviceChargeAmount);
        String code = CommonUtil.createSerialNumber(EOrderPrefix.WITHDRAWAL_CODE.getValue());
        //汇率
        CurrencyDTO currencyDTO = baseService.getCurrency(pkCountry);

        CuMemberWithdraw cuMemberWithdraw = CuMemberWithdraw.builder().pkMember(pkMember)
                .pkAccount(pkAccount).pkBank(pkBank).remarks(cuMemberWithdrawParam.getRemarks())
                .pkRate(currencyDTO.getPkId()).cashAmount(cashAmount)
                .serviceCharge(serviceChargeAmount).incomeTax(payIncomeTax)
                .issuedAmount(issuedAmount).withdrawCode(code).build();
        cuMemberWithdraw.setApproveState(EApproveStatus.WAIT_SUBMIT.getValue());
        cuMemberWithdraw.setDelFlag(EDelFlag.UN_DELETE.getValue());
        cuMemberWithdraw.setPkCountry(pkCountry);
        cuMemberWithdraw.setPkCreator(pkMember);
        return toAjax(cuMemberWithdrawService.saveMemberWithdrawInfo(cuMemberWithdraw));

    }

    /**
     * 是否可以提现
     *
     * @return AjaxResult
     */
    @GetMapping("/is-withdraw")
    public AjaxResult withdrawCycle() {

        Long pkMember = SecurityUtils.getUserId();
        log.info("----------提现会员Id {} ：" + pkMember);
        String memberCode = SecurityUtils.getMemberCode();
         log.info("----------提现会员编号{} ：" + memberCode);
        Integer isWithdraw = isWithdraw();
        AjaxResult ajaxResult = new AjaxResult();
        if (isWithdraw.equals(EYesNo.NO.getIntValue())) {
            ajaxResult.put("code", EYesNo.NO.getIntValue());
            ajaxResult.put("msg", TransactionUtils.getContent(FinanceMsgConstants.WITHDRAW_CYCLE));
        } else {
            ajaxResult.put("code", EYesNo.YES.getIntValue());
        }
        return ajaxResult;
    }


    /**
     * 提现周期（周一、周五可提现）
     *
     * @return int
     */
    private Integer getWithdrawCycle() {
        // TODO: 2024/1/9  打印提现时间
        printDate();
        LocalDate localDate = LocalDate.now();
        DayOfWeek dayOfWeek = localDate.getDayOfWeek();
        Integer dayOfWeekNum = dayOfWeek.getValue();
        log.info("----------提现时间周期 ：" + dayOfWeekNum);
        String[] cycles = MagicNumberConstants.WITHDRAW_CYCLE.split(",");
        for (String cycle : cycles) {
            if (dayOfWeekNum.equals(Integer.parseInt(cycle))) {
                return EYesNo.YES.getIntValue();
            }
        }
        return EYesNo.NO.getIntValue();
    }


    private Integer isWithdraw() {
        Integer countrys[] = new Integer[]{105, 147, 139, 140, 26, 137, 138};
        Integer isWithdrawSatus = EYesNo.NO.getIntValue();
        LocalDate localDate = LocalDate.now();
        LocalDate initDate = LocalDate.parse(MagicNumberConstants.WITHDRAW_DATE);
        if (localDate.isAfter(initDate)) {
            return getWithdrawCycle();
        } else {
            Integer pkCountry = SecurityUtils.getPkCountry();
            for (Integer country:countrys) {
                if(country.equals(pkCountry)){
                    isWithdrawSatus = EYesNo.YES.getIntValue();
                    break;
                }else {
                    isWithdrawSatus= getWithdrawCycle();
                }
            }
        }
        return isWithdrawSatus;
    }

    private void printDate() {
        LocalDateTime localDate = LocalDateTime.now();
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String localDateStr = localDate.format(fmt);
        log.info("----------提现时间 ：" + localDateStr);
    }


    /**
     * 取余
     *
     * @param amount
     * @return Boolean
     */
    private static Boolean remainder(BigDecimal amount) {
        BigDecimal[] results = amount.divideAndRemainder(BigDecimal.valueOf(MagicNumberConstants.WITHDRAW_MULTIPLE));
        if (results[1].compareTo(BigDecimal.ZERO) == 0) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }


    /**
     * 获取余额
     *
     * @param accountsType    账户值
     * @param cuMemberAccount 账户信息
     * @return BigDecimal
     */
    private BigDecimal getAvailableBalance(Integer accountsType, CuMemberAccount cuMemberAccount) {
        BigDecimal balance;
        //如果是奖金账户，取可提现金额
        if (accountsType.equals(EAccount.BONUS.getValue())) {
            balance = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.WITHDRAW_ACCOUNT + accountsType);
            BigDecimal lockAccount = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.LOCK_WITHDRAW_ACCOUNT + accountsType);

            if (null != lockAccount && lockAccount.compareTo(BigDecimal.ZERO) > 0) {
                balance = balance.subtract(lockAccount);
            }
        } else {
            //其它取配置账户余额
            //账户金额
            BigDecimal account = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.ACCOUNT + accountsType);
            account = account == null ? BigDecimal.ZERO : account;
            //锁定消费
            BigDecimal lockConsume = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.LOCK_ACCOUNT + accountsType);
            lockConsume = lockConsume == null ? BigDecimal.ZERO : lockConsume;
            //锁定转账
            BigDecimal lockTransfer = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.LOCK_TRANSFER_ACCOUNT + accountsType);
            lockTransfer = lockTransfer == null ? BigDecimal.ZERO : lockTransfer;
            balance = account.subtract(lockConsume).subtract(lockTransfer);
        }
        return balance;
    }



    /**
     * 是否为整数值
     *
     * @param bd 入参
     * @return boolean
     */
    private static Boolean isIntegerValue(BigDecimal bd) {
        boolean ret;
        try {
            bd.toBigIntegerExact();
            ret = true;
        } catch (ArithmeticException ex) {
            ret = false;
        }
        return ret;
    }


    /**
     * 查询列表(会员端)
     *
     * @return TableDataInfo
     */
    @GetMapping("/list-detail")
    public TableDataInfo memberWithdrawDetail() {
        startPage();
        Object[] objects = cuMemberWithdrawService.selectMemberWithdrawListByPkMember(SecurityUtils.getUserId(), SecurityUtils.getPkCountry());
        //处理分页
        TableDataInfo tableDataInfo = getDataTable((List<CuMemberWithdrawExt>) objects[0]);
        tableDataInfo.setRows((List<CuMemberWithdrawVO>) objects[1]);
        return tableDataInfo;
    }

    @GetMapping("/cancel")
    public AjaxResult cancelMemberWithdrawD(Long pkId) {
        CuMemberWithdraw cuMemberWithdraw = cuMemberWithdrawService.getById(pkId);
        if (cuMemberWithdraw.getApproveState().equals(EApproveStatus.WAIT_SUBMIT.getValue()) && cuMemberWithdraw.getStatus().equals(EWithdrawStatus.NORMAL.getValue())) {
            return toAjax(cuMemberWithdrawService.updateWithdrawStatusByPkId(pkId, SecurityUtils.getUserId()));
        } else {
            return AjaxResult.error(TransactionUtils.getContent(FinanceMsgConstants.WITHDRAWAL_NOT_CANCEL));
        }
    }


}
