package com.mmc.iuav.user.service.xzsz.impl;

import com.alibaba.fastjson2.JSONObject;
import com.mmc.iuav.general.CodeUtil;
import com.mmc.iuav.page.PageResult;
import com.mmc.iuav.response.ResultBody;
import com.mmc.iuav.response.ResultEnum;
import com.mmc.iuav.user.controller.WxController;
import com.mmc.iuav.user.dao.RealNameAuthDao;
import com.mmc.iuav.user.dao.UserServiceDao;
import com.mmc.iuav.user.dao.UserSubInfoDao;
import com.mmc.iuav.user.dao.wallet.PayWalletDao;
import com.mmc.iuav.user.dao.xzsz.WithdrawalDao;
import com.mmc.iuav.user.dao.xzsz.XzDao;
import com.mmc.iuav.user.entity.*;
import com.mmc.iuav.user.entity.wallet.PayWalletDO;
import com.mmc.iuav.user.entity.wallet.WithdrawalLogDO;
import com.mmc.iuav.user.enums.WithdrawalApplyStatus;
import com.mmc.iuav.user.enums.WithdrawalMethod;
import com.mmc.iuav.user.enums.XzEnums;
import com.mmc.iuav.user.model.dto.LoginSuccessDTO;
import com.mmc.iuav.user.model.dto.wallet.CashAmountDTO;
import com.mmc.iuav.user.model.dto.wallet.WithdrawalApplyDTO;
import com.mmc.iuav.user.model.dto.xzsz.CashPoolingDTO;
import com.mmc.iuav.user.model.qo.wallet.WalletFlowQO;
import com.mmc.iuav.user.model.qo.wallet.WithdrawalApplyQO;
import com.mmc.iuav.user.model.vo.WxMsgVO;
import com.mmc.iuav.user.model.vo.XzWithdrawalVO;
import com.mmc.iuav.user.model.vo.wallet.ApplyWithdrawalVO;
import com.mmc.iuav.user.service.WxService;
import com.mmc.iuav.user.service.xzsz.WithdrawalService;
import com.mmc.iuav.user.service.xzsz.XzService;
import com.mmc.iuav.user.util.SmsUtil;
import com.mmc.iuav.user.util.TDateUtil;
import com.mmc.iuav.user.xzsz.SingleSubmitResp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author: zj
 * @Date: 2023/8/23 16:09
 */
@Service
@Slf4j
public class WithdrawalServiceImpl implements WithdrawalService {
    @Autowired
    private WithdrawalDao withdrawalDao;

    @Autowired
    private XzDao xzDao;

    @Resource
    private RealNameAuthDao realNameAuthDao;

    @Autowired
    private PayWalletDao payWalletDao;

    @Autowired
    private XzService xzService;

    @Autowired
    private UserServiceDao userServiceDao;

    @Autowired
    private WxService wxService;

    @Autowired
    private UserSubInfoDao userSubInfoDao;

    @Override
    @Transactional
    public ResultBody apply(ApplyWithdrawalVO applyWithdrawalVO, Integer userAccountId) {
        // 判断该用户是否实名认证
        RealNameAuthDO realNameAuth = realNameAuthDao.getRealNameAuthByUId(userAccountId);
        if (realNameAuth != null && !realNameAuth.getCheckStatus().equals(1)) {
            return ResultBody.error("实名认证未通过!");
        }
        if (realNameAuth == null) {
            return ResultBody.error(ResultEnum.PLEASE_ERFORM_REAL_NAME_AUTHENTICATION_FIRST);
        }
        // 确保已电签
        XzAuthDO xzAuth = xzDao.getXzAuthByUserAccountId(userAccountId);
        if (xzAuth != null && !xzAuth.getXzAuthStatus().equals(1)) {
            return ResultBody.error("电签未通过!");
        }
        if (xzAuth == null) {
            return ResultBody.error("请先完成电签操作!");
        }
        // 当前提现金额是否足够
        PayWalletDO payWallet = payWalletDao.getPayWalletByUser(userAccountId);
        BigDecimal salaryAmt = payWallet.getSalaryAmt();
        if (salaryAmt.compareTo(applyWithdrawalVO.getPayAmount()) < 0) {
            return ResultBody.error("当前金额大于可提现金额!");
        }
        applyWithdrawalVO.setUserAccountId(userAccountId);
        // 生成提现交易编号
        String outerTradeNo = "B" + TDateUtil.getDateStr(new Date(), TDateUtil.TYPE) + userAccountId + CodeUtil.getRandomNum(4);
        // 记录提现申请记录
        XzWithdrawalApplyDO xzWithdrawalApplyDO = new XzWithdrawalApplyDO(applyWithdrawalVO);
        xzWithdrawalApplyDO.setOuterTradeNo(outerTradeNo);
        xzWithdrawalApplyDO.setEmpName(applyWithdrawalVO.getEmpName());
        xzWithdrawalApplyDO.setEmpPhone(applyWithdrawalVO.getEmpPhone());
        xzWithdrawalApplyDO.setLicenseId(realNameAuth.getIdNumber());
        xzWithdrawalApplyDO.setLicenseType("ID_CARD");
        xzWithdrawalApplyDO.setMonth(TDateUtil.getCurrentDateByType("yyyy-MM"));
        xzWithdrawalApplyDO.setTradeStatus("apply");
        withdrawalDao.insertWithdrawalApply(xzWithdrawalApplyDO);
        // 生成提现流水编号
        String payNo = "T" + TDateUtil.getDateStr(new Date(), TDateUtil.TYPE) + userAccountId + CodeUtil.getRandomNum(4);
        // 记录流水记录
        WithdrawalLogDO withdrawalLogDO = new WithdrawalLogDO();
        withdrawalLogDO.setPayNo(payNo);
        withdrawalLogDO.setPayTime(new Date());
        withdrawalLogDO.setSalaryFreeze(applyWithdrawalVO.getPayAmount());
        withdrawalLogDO.setSalaryPaid(BigDecimal.ZERO);
        withdrawalLogDO.setXzWithdrawalApplyId(xzWithdrawalApplyDO.getId());
        withdrawalLogDO.setUserAccountId(userAccountId);
        withdrawalLogDO.setPayMethod(WithdrawalMethod.TXDJ.getCode());
        payWalletDao.insertWithdrawalLog(withdrawalLogDO);
        // 修改钱包信息，钱包冻结金额
        PayWalletDO payWalletDO = new PayWalletDO();
        payWalletDO.setPid(payWallet.getPid());
        payWalletDO.setUserAccountId(userAccountId);
        payWalletDO.setSalaryAmt(payWallet.getSalaryAmt().subtract(applyWithdrawalVO.getPayAmount()));
        payWalletDO.setWdlFreeze(payWallet.getWdlFreeze().add(applyWithdrawalVO.getPayAmount()));
        int updateCount = payWalletDao.updatePayWallet(payWalletDO);
        if (updateCount != 1) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResultBody.error("提现申请失败，请稍后重试!");
        }
        return ResultBody.success(xzWithdrawalApplyDO.getId());
    }


    @Override
    public ResultBody withdrawalList(Integer userAccountId, WalletFlowQO param) {
        if (!StringUtils.isBlank(param.getYearMonth())) {
            param.setEndTime(TDateUtil.getDateStr(
                    TDateUtil.getMonthLatestDay(TDateUtil.getDate(param.getYearMonth() + "-01", "yyyy-MM-dd")),
                    "yyyy-MM-dd") + " 23:59:59");
        }
        param.setUserAccountId(userAccountId);
        int count = payWalletDao.countPayWithdrawalLog(param);
        if (count == 0) {
            return ResultBody.success(PageResult.buildPage(param.getPageNo(), param.getPageSize(), count));
        }
        Integer pageNo = param.getPageNo();
        param.buildCurrentPage();
        List<XzWithdrawalApplyDO> withdrawalLogList = payWalletDao.getWithdrawalListByUserAccountId(param);
        return ResultBody.success(PageResult.buildPage(pageNo, param.getPageSize(), count, withdrawalLogList.stream()
                .map(XzWithdrawalApplyDO::buildUserBillingDetailVO).collect(Collectors.toList())));
    }


    @Override
    public PageResult listPageWithdrawalApply(WithdrawalApplyQO param) {
        int count = payWalletDao.countWithdrawalApply(param);
        if (count == 0) {
            return PageResult.buildPage(param.getPageNo(), param.getPageSize(), count);
        }
        Integer pageNo = param.getPageNo();
        param.buildCurrentPage();
        List<XzWithdrawalApplyDO> list = payWalletDao.listPageWithdrawalApply(param);
        List<WithdrawalApplyDTO> pageList = list.stream().map(XzWithdrawalApplyDO::buildWithdrawalApplyDTO).collect(Collectors.toList());
        return PageResult.buildPage(pageNo, param.getPageSize(), count, pageList);
    }

    @Override
    @Transactional
    public ResultBody approveWithdrawalApply(Integer id, Integer applyStatus, Integer approveUserAccountId, String remark) {
        if (!WithdrawalApplyStatus.TXCG.getCode().toString().equals(applyStatus.toString())
                && !WithdrawalApplyStatus.TXSB.getCode().toString().equals(applyStatus.toString())) {
            return ResultBody.error(ResultEnum.WITHDRAWAL_APPLY_STATUS_ERROR);
        }

        // 查询申请单信息
        XzWithdrawalApplyDO applyInfo = payWalletDao.getWithdrawalApplyByIdOrOuterTradeNo(id, null);
        if (applyInfo == null) {
            return ResultBody.error(ResultEnum.WITHDRAWAL_INFO_NOT_FIND_ERROR);
        }
        if (!(WithdrawalApplyStatus.TXSQ.getCode().toString()).equals(applyInfo.getApplyStatus().toString())) {
            return ResultBody.error(ResultEnum.WITHDRAWAL_REPEAT_CHECK_ERROR);
        }

        // 获取当前用户钱包信息
        PayWalletDO wallet = payWalletDao.getPayWalletByUser(applyInfo.getUserAccountId());

        // 修改申请单的操作人信息
        XzWithdrawalApplyDO apply = new XzWithdrawalApplyDO();
        apply.setId(id);
        apply.setApplyStatus(applyStatus);
        apply.setRemark(remark);
        apply.setApproveUser(approveUserAccountId);
        apply.setApproveTime(new Date());

        payWalletDao.updateWithdrawalApply(apply);

        if (WithdrawalApplyStatus.TXCG.getCode().toString().equals(applyStatus.toString())) {
            // 如果判断审批状态是成功，那么就调用小猪结算提现接口
            XzWithdrawalVO xzWithdrawalVO = new XzWithdrawalVO();
            xzWithdrawalVO.setUserAccountId(applyInfo.getUserAccountId());
            xzWithdrawalVO.setMonth(applyInfo.getMonth());
            xzWithdrawalVO.setOuterTradeNo(applyInfo.getOuterTradeNo());
            xzWithdrawalVO.setEmpName(applyInfo.getEmpName());
            xzWithdrawalVO.setEmpPhone(applyInfo.getEmpPhone());
            xzWithdrawalVO.setLicenseType(applyInfo.getLicenseType());
            xzWithdrawalVO.setLicenseId(applyInfo.getLicenseId());
            xzWithdrawalVO.setSettleType(applyInfo.getSettleType());
            xzWithdrawalVO.setPayAccount(applyInfo.getPayAccount());
            xzWithdrawalVO.setBankName(applyInfo.getBankName());
            xzWithdrawalVO.setPositionName(applyInfo.getPositionName());
            xzWithdrawalVO.setPayAmount(applyInfo.getPayAmount());
            SingleSubmitResp singleSubmitResp = xzService.singleSubmit(xzWithdrawalVO);
            if (XzEnums.F.getCode().equals(singleSubmitResp.getIsSuccess())) {
                // 更新提现申请记录
                XzWithdrawalApplyDO xzWithdrawalApplyDO = new XzWithdrawalApplyDO();
                xzWithdrawalApplyDO.setOuterTradeNo(applyInfo.getOuterTradeNo());
                xzWithdrawalApplyDO.setTradeResult(XzEnums.failure.getName());
                xzWithdrawalApplyDO.setTradeStatus(XzEnums.failure.getCode());
                xzWithdrawalApplyDO.setErrorCode(singleSubmitResp.getErrorCode());
                xzWithdrawalApplyDO.setErrorMessage(singleSubmitResp.getErrorMessage());
                payWalletDao.updateWithdrawalApply(xzWithdrawalApplyDO);
                // 回滚用户钱包金额
                rollbackPayWallet(applyInfo, wallet);
            }
        } else {
            // 审批未通过 退回金额 解除冻结
            // 更新提现申请记录
            XzWithdrawalApplyDO xzWithdrawalApplyDO = new XzWithdrawalApplyDO();
            xzWithdrawalApplyDO.setOuterTradeNo(applyInfo.getOuterTradeNo());
            xzWithdrawalApplyDO.setTradeResult("审批未通过");
            xzWithdrawalApplyDO.setTradeStatus("approve");
            payWalletDao.updateWithdrawalApply(xzWithdrawalApplyDO);
            int updateCount = rollbackPayWallet(applyInfo, wallet);
            if (updateCount != 1) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return ResultBody.error("操作失败，请稍后重试!");
            }
        }
        String userPhone = userServiceDao.getUserPhoneByUserId(applyInfo.getUserAccountId());
        SmsUtil.sendPassWithdrawalApply(userPhone);

        // 公众号消息通知提现成功
        WxMsgVO ws = new WxMsgVO();
        String unionId = userServiceDao.getUserAccountById(applyInfo.getUserAccountId()).getUnionId();
        // 查询对应的openId(touser)
        UserSubInfoDO info = userSubInfoDao.getUserSubInfoByUnionId(unionId);
        if(info != null && info.getOpenId() != null){
            String touser = info.getOpenId();
            JSONObject jsonObject = spellMsg(applyInfo.getEmpName(), applyInfo.getPayAmount(), applyInfo.getPayAccount());
            ws.setTouser(touser);
            ws.setTemplateId("y6PHvZownxqR5hf4dSXaa2Lp1jeq3ccytd6G-kUQla4");
            ws.setDataObject(jsonObject);
            wxService.sendSubTemplateMsg(ws);
        }
        return ResultBody.success();
    }


    @Transactional(rollbackFor = Exception.class)
    public int rollbackPayWallet(XzWithdrawalApplyDO applyInfo, PayWalletDO wallet) {
        // 生成提现流水编号
        String payNo = "T" + TDateUtil.getDateStr(new Date(), TDateUtil.TYPE) + applyInfo.getUserAccountId() + CodeUtil.getRandomNum(4);
        // 记录流水记录
        WithdrawalLogDO withdrawalLogDO = new WithdrawalLogDO();
        withdrawalLogDO.setPayNo(payNo);
        withdrawalLogDO.setPayTime(new Date());
        withdrawalLogDO.setSalaryPaid(BigDecimal.valueOf(applyInfo.getPayAmount()));
        withdrawalLogDO.setXzWithdrawalApplyId(applyInfo.getId());
        withdrawalLogDO.setUserAccountId(applyInfo.getUserAccountId());
        withdrawalLogDO.setPayMethod(WithdrawalMethod.TXSB.getCode());
        withdrawalLogDO.setSalaryFreeze(new BigDecimal(0));
        payWalletDao.insertWithdrawalLog(withdrawalLogDO);
        // 修改钱包信息，钱包冻结金额
        PayWalletDO payWalletDO = new PayWalletDO();
        payWalletDO.setPid(wallet.getPid());
        payWalletDO.setUserAccountId(applyInfo.getUserAccountId());
        payWalletDO.setSalaryAmt(wallet.getSalaryAmt().add(BigDecimal.valueOf(applyInfo.getPayAmount())));
        payWalletDO.setWdlFreeze(wallet.getWdlFreeze().subtract(BigDecimal.valueOf(applyInfo.getPayAmount())));
        return payWalletDao.updatePayWallet(payWalletDO);
    }

    @Override
    public CashAmountDTO getCashAmountAndWithdrawAmount(LoginSuccessDTO loginSuccessDTO) {
        if (!loginSuccessDTO.getRoleInfo().getSuperAdmin().equals(1)) {
            return null;
        }
        CashAmountDTO cashAmountDTO = new CashAmountDTO();
        BigDecimal totalWithdrawAmount = payWalletDao.getTotalWithdrawAmount();
        cashAmountDTO.setTotalWithdrawAmt(totalWithdrawAmount);
        ResultBody cashPooling = xzService.getCashPooling();
        String s = JSONObject.toJSONString(cashPooling.getResult());
        CashPoolingDTO cashPoolingDTO = JSONObject.parseObject(s, CashPoolingDTO.class);
        cashAmountDTO.setCashPoolAmount(cashPoolingDTO.getAvailableBalance());
        return cashAmountDTO;
    }

    public JSONObject spellMsg(String empName, Double payAmount, String payAccount){
        JSONObject data=new JSONObject();

        //提现商户：{{keyword1.DATA}}
        JSONObject keyword1=new JSONObject();
        keyword1.put("value",empName);
        data.put("keyword1",keyword1);

        //提现金额：{{keyword2.DATA}}
        JSONObject keyword2=new JSONObject();
        keyword2.put("value",payAmount);
        data.put("keyword2",keyword2);

        //提现账户：{{keyword3.DATA}}
        JSONObject keyword3=new JSONObject();
        keyword3.put("value",payAccount);
        data.put("keyword3",keyword3);

        //处理时间：{{keyword4.DATA}}
        JSONObject keyword4=new JSONObject();
        keyword4.put("value",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        data.put("keyword4",keyword4);
        return data;
    }

}
