package com.ruoyi.ss.transfer.service.impl;

import com.alipay.api.response.AlipayFundTransCommonQueryResponse;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.pay.ali.enums.AliTransferStatus;
import com.ruoyi.common.pay.ali.service.AliTransferService;
import com.ruoyi.common.pay.wx.domain.enums.WxTransferBatchStatus;
import com.ruoyi.common.pay.wx.domain.enums.WxTransferDetailStatus;
import com.ruoyi.common.pay.wx.service.WxPayService;
import com.ruoyi.common.pay.wx.service.WxTransferService;
import com.ruoyi.common.pay.wx.util.WxPayUtil;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.SnowFlakeUtil;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.ss.account.domain.enums.AccountType;
import com.ruoyi.ss.transfer.domain.Transfer;
import com.ruoyi.ss.transfer.domain.TransferQuery;
import com.ruoyi.ss.transfer.domain.TransferVO;
import com.ruoyi.ss.transfer.domain.enums.TransferBstType;
import com.ruoyi.ss.transfer.domain.enums.TransferStatus;
import com.ruoyi.ss.transfer.interfaces.AfterTransfer;
import com.ruoyi.ss.transfer.mapper.TransferMapper;
import com.ruoyi.ss.transfer.service.TransferAssembler;
import com.ruoyi.ss.transfer.service.TransferService;
import com.ruoyi.ss.transferDetail.domain.TransferDetail;
import com.ruoyi.ss.transferDetail.domain.TransferDetailQuery;
import com.ruoyi.ss.transferDetail.domain.TransferDetailVO;
import com.ruoyi.ss.transferDetail.domain.enums.TransferDetailStatus;
import com.ruoyi.ss.transferDetail.service.ITransferDetailService;
import com.wechat.pay.java.service.transferbatch.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * 转账Service业务层处理
 *
 * @author ruoyi
 * @date 2024-08-09
 */
@Service
@Slf4j
public class TransferServiceImpl implements TransferService
{
    @Autowired
    private TransferMapper transferMapper;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private ITransferDetailService transferDetailService;

    @Autowired
    private WxPayService wxPayService;

    @Autowired
    private TransferAssembler transferAssembler;

    @Autowired
    private WxTransferService wxTransferService;

    @Autowired
    private AliTransferService aliTransferService;

    /**
     * 查询转账
     *
     * @param batchId 转账主键
     * @return 转账
     */
    @Override
    public TransferVO selectTransferByBatchId(Long batchId)
    {
        return transferMapper.selectTransferByBatchId(batchId);
    }

    /**
     * 查询转账列表
     *
     * @param transfer 转账
     * @return 转账
     */
    @Override
    public List<TransferVO> selectTransferList(TransferQuery transfer)
    {
        return transferMapper.selectTransferList(transfer);
    }

    /**
     * 新增转账
     *
     * @param transfer 转账
     * @return 结果
     */
    @Override
    public int insertTransfer(Transfer transfer)
    {
        transfer.setCreateTime(DateUtils.getNowDate());
        transfer.setBatchNo(String.valueOf(SnowFlakeUtil.newId()));
        return transferMapper.insertTransfer(transfer);
    }

    /**
     * 修改转账
     *
     * @param transfer 转账
     * @return 结果
     */
    @Override
    public int updateTransfer(Transfer transfer)
    {
        return transferMapper.updateTransfer(transfer);
    }

    /**
     * 批量删除转账
     *
     * @param batchIds 需要删除的转账主键
     * @return 结果
     */
    @Override
    public int deleteTransferByBatchIds(Long[] batchIds)
    {
        return transferMapper.deleteTransferByBatchIds(batchIds);
    }

    /**
     * 删除转账信息
     *
     * @param batchId 转账主键
     * @return 结果
     */
    @Override
    public int deleteTransferByBatchId(Long batchId)
    {
        return transferMapper.deleteTransferByBatchId(batchId);
    }

    @Override
    public int insertWithDetail(TransferVO vo) {
        Integer result = transactionTemplate.execute(status -> {
            int insert = this.insertTransfer(vo);
            ServiceUtil.assertion(insert != 1, "新增转账失败");

            if (CollectionUtils.isNotEmptyElement(vo.getDetailList())) {
                for (TransferDetailVO detail : vo.getDetailList()) {
                    detail.setTransferId(vo.getBatchId());
                }
                int batch = transferDetailService.batchInsert(vo.getDetailList());
                ServiceUtil.assertion(batch != vo.getDetailList().size(), "新增转账明细失败");
            }

            return insert;
        });

        return result == null ? 0 : result;
    }

    @Override
    public boolean requestTransfer(String batchNo) {
        TransferVO transfer = this.selectByBatchNo(batchNo);
        transferAssembler.assembleDetail(Collections.singletonList(transfer));
        return this.requestTransfer(transfer);
    }

    /**
     * 请求转账
     */
    private boolean requestTransfer(TransferVO transfer) {
        if (transfer == null || transfer.getBatchId() == null) {
            return false;
        }

        // 请求转账
        Boolean result = transactionTemplate.execute(status -> {
            // 修改状态
            Transfer data = new Transfer();
            data.setStatus(TransferStatus.TRANSFER_ING.getStatus());
            TransferQuery query = new TransferQuery();
            query.setBatchId(transfer.getBatchId());
            query.setStatus(TransferStatus.WAIT_TRANSFER.getStatus());
            int update = this.updateByQuery(data, query);
            ServiceUtil.assertion(update != 1, "更新转账状态失败");

            // 更新子表状态
            TransferDetail detailData = new TransferDetail();
            detailData.setStatus(TransferDetailStatus.TRANSFER_ING.getStatus());
            TransferDetailQuery detailQuery = new TransferDetailQuery();
            detailQuery.setTransferId(transfer.getBatchId());
            detailQuery.setStatus(TransferDetailStatus.WAIT_TRANSFER.getStatus());
            int updateDetail = transferDetailService.updateByQuery(detailData, detailQuery);
            ServiceUtil.assertion(updateDetail != 1, "更新转账明细状态失败");

            // 发起转账
            if (AccountType.WECHAT.getType().equals(transfer.getAccountType())) {
                wxTransferService.batchTransfer(transfer);
            } else if (AccountType.ALIPAY.getType().equals(transfer.getAccountType())) {
                aliTransferService.transfer(transfer);
            } else {
                throw new ServiceException("暂不支持该方式进行线上转账");
            }

            return true;
        });

        return result != null && result;
    }

    @Override
    public TransferVO selectByBatchNo(String batchNo) {
        return transferMapper.selectByBatchNo(batchNo);
    }

    @Override
    public int updateByQuery(Transfer data, TransferQuery query) {
        return transferMapper.updateByQuery(data, query);
    }

    @Override
    public int refreshTransferStatus(TransferVO transfer) {
        if (transfer == null) {
            return 0;
        }
        // 微信
        if (AccountType.WECHAT.getType().equals(transfer.getAccountType())) {
            return this.refreshTransferStatusWx(transfer);
        } else if (AccountType.ALIPAY.getType().equals(transfer.getAccountType())) {
            return this.refreshTransferStatusAli(transfer);
        } else {
            throw new ServiceException("该付款方式不支持刷新操作");
        }
    }

    private int refreshTransferStatusAli(TransferVO transfer) {
        if (transfer == null) {
            return 0;
        }

        // 待更新的数据
        Transfer data = new Transfer();
        List<TransferDetail> detaiList = new ArrayList<>();

        int success = 0;
        for (TransferDetailVO detail : transfer.getDetailList()) {
            AlipayFundTransCommonQueryResponse res = aliTransferService.getTransferBatchByOutNo(detail.getDetailNo());

            TransferDetail updateDetail = new TransferDetail();
            updateDetail.setDetailId(detail.getDetailId());

            // 成功的情况
            if (res != null && AliTransferStatus.successList().contains(res.getStatus())) {
                updateDetail.setStatus(TransferDetailStatus.TRANSFER_SUCCESS.getStatus());
                detaiList.add(updateDetail);
                success ++;
            }
            // 失败的情况
            else if (res == null || AliTransferStatus.failList().contains(res.getStatus())){
                updateDetail.setStatus(TransferDetailStatus.TRANSFER_FAIL.getStatus());
                if (res != null) {
                    updateDetail.setStatus(res.getFailReason());
                } else {
                    updateDetail.setStatus("未知错误，返回值为空");
                }
                detaiList.add(updateDetail);
            }
            // 其余情况不处理
        }

        data.setUpdateTime(DateUtils.getNowDate());
        // 全部成功
        if (success == transfer.getDetailList().size()) {
            data.setStatus(TransferStatus.TRANSFER_SUCCESS.getStatus());
        }
        // 全部失败
        else if (success == 0) {
            data.setStatus(TransferStatus.TRANSFER_FAIL.getStatus());
        }
        // 部分成功
        else {
            data.setStatus(TransferStatus.TRANSFER_PART_SUCCESS.getStatus());
        }

        // 保存到数据库
        return this.saveByRefresh(transfer.getBatchId(), data, detaiList);
    }

    private void operatorBiz(Long batchId) {
        // 查询最新的转账信息
        TransferVO dbTransfer = selectTransferByBatchId(batchId);
        transferAssembler.assembleDetail(Collections.singletonList(dbTransfer));

        TransferBstType bstType = TransferBstType.parse(dbTransfer.getBstType());
        ServiceUtil.assertion(bstType == null, "业务类型不存在");
        if (bstType.getAfterTransfer() != null) {
            // 业务处理器
            AfterTransfer afterTransfer = SpringUtils.getBean(bstType.getAfterTransfer());

            // 业务返回值
            int bstResult = 0;
            // 成功
            if (TransferStatus.TRANSFER_SUCCESS.getStatus().equals(dbTransfer.getStatus())) {
                bstResult = afterTransfer.onTransferSuccess(dbTransfer);
            }
            // 部分成功
            else if (TransferStatus.TRANSFER_PART_SUCCESS.getStatus().equals(dbTransfer.getStatus())) {
                bstResult = afterTransfer.onTransferPartSuccess(dbTransfer);
            }
            // 失败
            else if (TransferStatus.TRANSFER_FAIL.getStatus().equals(dbTransfer.getStatus())) {
                bstResult = afterTransfer.onTransferFail(dbTransfer);
            }
            ServiceUtil.assertion(bstResult == 0, "业务执行失败");
        }
    }

    @Override
    public int refreshTransferStatus(Long batchId) {
        TransferVO transfer = selectTransferByBatchId(batchId);
        transferAssembler.assembleDetail(Collections.singletonList(transfer));
        return this.refreshTransferStatus(transfer);
    }

    private int refreshTransferStatusWx(TransferVO transfer) {
        if (transfer == null) {
            return 0;
        }
        // 主表信息
        GetTransferBatchByOutNoRequest request = new GetTransferBatchByOutNoRequest();
        request.setOutBatchNo(transfer.getBatchNo());
        request.setNeedQueryDetail(false);
        TransferBatchEntity transferBatchEntity = wxTransferService.getTransferBatchByOutNo(request);
        if (transferBatchEntity == null || transferBatchEntity.getTransferBatch() == null) {
            return 0;
        }
        // 批次信息
        TransferBatchGet transferBatch = transferBatchEntity.getTransferBatch();
        String batchStatus = transferBatch.getBatchStatus();

        // 仅处理完成和关单的状态
        log.info("【刷新微信转账状态】批次信息：{}", transferBatch);
        if (!WxTransferBatchStatus.asList(WxTransferBatchStatus.FINISHED, WxTransferBatchStatus.CLOSED).contains(batchStatus)) {
            return 1;
        }

        // 待更新的数据
        Transfer data = new Transfer();
        List<TransferDetail> detaiList = new ArrayList<>();

        data.setUpdateTime(DateUtils.toDateByRfc3339(transferBatch.getUpdateTime()));
        // 已完成：所有明细都处理完成了
        if (WxTransferBatchStatus.FINISHED.getStatus().equals(transferBatch.getBatchStatus())) {
            if (transferBatch.getSuccessNum() != null && Objects.equals(transferBatch.getSuccessNum(), transferBatch.getTotalNum())) {
                // 全部成功
                data.setStatus(TransferStatus.TRANSFER_SUCCESS.getStatus());
            } else if (transferBatch.getFailNum() != null && Objects.equals(transferBatch.getFailNum(), transferBatch.getTotalNum())) {
                // 全部失败
                data.setStatus(TransferStatus.TRANSFER_FAIL.getStatus());
            } else {
                // 部分成功
                data.setStatus(TransferStatus.TRANSFER_PART_SUCCESS.getStatus());
            }

            // 处理明细信息
            detaiList.addAll(this.buildRefreshDetailList(transfer.getDetailList()));
        }
        // 关单：失败，并给出关单原因
        else if (WxTransferBatchStatus.CLOSED.getStatus().equals(transferBatch.getBatchStatus())) {
            data.setStatus(TransferStatus.TRANSFER_FAIL.getStatus());
            data.setCloseReason(WxPayUtil.getTransferCLoseReason(transferBatch.getCloseReason().name()));
            // 所有明细都修改为失败
            for (TransferDetailVO detail : transfer.getDetailList()) {
                TransferDetail failDetail = new TransferDetail();
                failDetail.setDetailId(detail.getDetailId());
                failDetail.setStatus(TransferDetailStatus.TRANSFER_FAIL.getStatus());
                detaiList.add(failDetail);
            }
        }

        // 保存到数据库
        return this.saveByRefresh(transfer.getBatchId(), data, detaiList);

    }

    private int saveByRefresh(Long batchId, Transfer data, List<TransferDetail> detaiList) {
        Integer result = transactionTemplate.execute(status -> {
            // 修改主表信息
            TransferQuery query = new TransferQuery();
            query.setStatus(TransferStatus.TRANSFER_ING.getStatus());
            query.setBatchId(batchId);
            int update = this.updateByQuery(data, query);
            ServiceUtil.assertion(update != 1, "修改转账批次失败，状态已发生变化");

            // 修改明细信息
            for (TransferDetail detail : detaiList) {
                TransferDetailQuery detailQuery = new TransferDetailQuery();
                detailQuery.setDetailId(detail.getDetailId());
                detailQuery.setStatus(TransferStatus.TRANSFER_ING.getStatus());
                int detailUpdate = transferDetailService.updateByQuery(detail, detailQuery);
                ServiceUtil.assertion(detailUpdate != 1, "转账明细修改失败，状态已发生变化");
            }

            // 操作业务信息
            this.operatorBiz(batchId);

            return update;
        });

        return result == null ? 0 : result;
    }

    private List<TransferDetail> buildRefreshDetailList(List<TransferDetailVO> detailList) {
        List<TransferDetail> updateList = new ArrayList<>();

        if (CollectionUtils.isEmptyElement(detailList)) {
            return updateList;
        }

        for (TransferDetailVO detail : detailList) {
            GetTransferDetailByOutNoRequest detailRequest = new GetTransferDetailByOutNoRequest();
            detailRequest.setOutBatchNo(detail.getTransferBatchNo());
            detailRequest.setOutDetailNo(detail.getDetailNo());
            TransferDetailEntity transferDetailEntity = wxTransferService.getTransferDetailByOutNo(detailRequest);
            log.info("【刷新微信转账状态】明细批次信息：{}", transferDetailEntity);
            if (transferDetailEntity == null) {
                continue;
            }

            TransferDetail updateDetail = new TransferDetail();
            updateDetail.setDetailId(detail.getDetailId());

            // 转账成功
            if (WxTransferDetailStatus.SUCCESS.getStatus().equals(transferDetailEntity.getDetailStatus())) {
                updateDetail.setStatus(TransferDetailStatus.TRANSFER_SUCCESS.getStatus());
                updateList.add(updateDetail);
            }
            // 转账失败
            else if (WxTransferDetailStatus.FAIL.getStatus().equals(transferDetailEntity.getDetailStatus())){
                updateDetail.setStatus(TransferDetailStatus.TRANSFER_FAIL.getStatus());
                updateDetail.setFailReason(WxPayUtil.getTransferDetailErrorMsg(transferDetailEntity.getFailReason().name()));
                updateList.add(updateDetail);
            }
        }
        return updateList;
    }


}
