package com.jeequan.jeepay.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.SysUser;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.bill.LocalBill;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.db.entity.*;
import com.jeequan.jeepay.service.mapper.CheckDiffMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 对账差异表 服务实现类
 * </p>
 *
 * @author [mybatis plus generator]
 * @since 2022-09-09
 */
@Service
public class CheckDiffService extends ServiceImpl<CheckDiffMapper, CheckDiff> {

    @Autowired private CheckBatchService checkBatchService;
    @Autowired private CheckChannelBillService checkChannelBillService;
    @Autowired private PayOrderService payOrderService;
    @Autowired private RefundOrderService refundOrderService;

    @Transactional
    public void saveBatchDiffBills(List<LocalBill> localDiffBills, List<CheckDiff> channelDiffBills, List<CheckDiff> orderDiffBills, CheckBatch updateCheckBatch) {

        List<CheckDiff> checkDiffList = new LinkedList<>();

        if (CollUtil.isNotEmpty(localDiffBills)) {
            checkDiffList.addAll(this.covertLocalBillToCheckDiff(localDiffBills));
        }

        if (CollUtil.isNotEmpty(channelDiffBills)) {
            checkDiffList.addAll(channelDiffBills);
        }

        if (CollUtil.isNotEmpty(orderDiffBills)) {
            checkDiffList.addAll(orderDiffBills);
        }

        // 有差异更新差异数量，无差异改状态为处理完成
        if (CollUtil.isNotEmpty(checkDiffList)) {
            boolean result = this.saveBatch(checkDiffList);
            if (!result) {
                throw new BizException("保存差异账单失败");
            }

            // 批次处理完成，更新差异数量
            updateCheckBatch.setDiffCount(checkDiffList.size());
            updateCheckBatch.setUnHandleDiffCount(checkDiffList.size());
        }else {
            if (updateCheckBatch.getReleaseState() != null && updateCheckBatch.getReleaseState() == CS.YES) {
                updateCheckBatch.setState(CS.YES);
            }
        }

        // 更新本地统计数据和差异数据
        checkBatchService.updateById(updateCheckBatch);
    }


    public CheckDiff covertToOrderCheckDiff(CheckChannelBill channelBill, LocalBill localBill, String diffType) {

        CheckDiff checkDiff = new CheckDiff();
        BeanUtil.copyProperties(localBill, checkDiff);
        BeanUtil.copyProperties(channelBill, checkDiff);

        checkDiff.setDiffType(diffType);
        checkDiff.setHandleState(CheckDiff.HANDLE_STATE_WAITING); // 差异处理状态：默认 待处理
        return checkDiff;
    }

    public CheckDiff covertToCheckDiff(LocalBill orderBill, String diffType) {

        CheckDiff checkDiff = new CheckDiff();
        BeanUtil.copyProperties(orderBill, checkDiff);

        checkDiff.setBatchNo(checkBatchService.getBatchNo(orderBill.getIfCode(), orderBill.getChannelMchNo(), orderBill.getBillDate()));
        checkDiff.setIfCode(orderBill.getIfCode());
        checkDiff.setChannelMchNo(orderBill.getChannelMchNo());
        checkDiff.setBillDate(orderBill.getBillDate());
        checkDiff.setDiffType(diffType);
        checkDiff.setMchAppId(orderBill.getMchAppId());
        checkDiff.setHandleState(CheckDiff.HANDLE_STATE_WAITING); // 差异处理状态：默认 待处理

        if (StringUtils.equalsAny(diffType, CheckDiff.DIFF_TYPE_LOCAL, CheckDiff.DIFF_TYPE_CHANNEL)) {
            checkDiff.setHandleState(CheckDiff.HANDLE_STATE_HANG_UP); // 差异处理状态：状态为挂账，可能是隔日订单造成的，待自动处理
        }

        return checkDiff;
    }

    /** 本地账单转换为差异账单 */
    public CheckDiff covertSingleLocalBillToLocalCheckDiff(LocalBill orderBill) {
        return covertToCheckDiff(orderBill, CheckDiff.DIFF_TYPE_LOCAL);
    }

    /** 本地账单  批量转换为差异账单 */
    public List<CheckDiff> covertLocalBillToCheckDiff(List<LocalBill> localBillList) {
        return localBillList.stream().map(this::covertSingleLocalBillToLocalCheckDiff).collect(Collectors.toList());
    }

    /** 渠道账单转换为差异账单 */
    public CheckDiff covertSingleChannelBillToCheckDiff(CheckChannelBill orderBill) {
        return covertToCheckDiff(orderBill, CheckDiff.DIFF_TYPE_CHANNEL);
    }

    /** 渠道账单  批量转换为差异账单 */
    public List<CheckDiff> covertChannelBillToCheckDiff(List<CheckChannelBill> channelBillList) {
        return channelBillList.stream().map(this::covertSingleChannelBillToCheckDiff).collect(Collectors.toList());
    }

    /** 渠道账单  批量转换为差异账单 */
    public CheckDiff covertToCheckDiff(CheckChannelBill orderBill, String diffType) {

        CheckDiff checkDiff = new CheckDiff();
        BeanUtil.copyProperties(orderBill, checkDiff);

        checkDiff.setBatchNo(orderBill.getBatchNo());
        checkDiff.setIfCode(orderBill.getIfCode());
        checkDiff.setChannelMchNo(orderBill.getChannelMchNo());
        checkDiff.setBillDate(orderBill.getBillDate());
        checkDiff.setDiffType(diffType);
        checkDiff.setHandleState(CheckDiff.HANDLE_STATE_WAITING); // 差异处理状态：默认 待处理

        if (StringUtils.equalsAny(diffType, CheckDiff.DIFF_TYPE_LOCAL, CheckDiff.DIFF_TYPE_CHANNEL)) {
            checkDiff.setHandleState(CheckDiff.HANDLE_STATE_HANG_UP); // 差异处理状态：状态为挂账，可能是隔日订单造成的，待自动处理
        }

        return checkDiff;
    }

    /** 更新差异单状态为已处理 */
    public void updateHandleStateSuccess(List<CheckDiff> checkSuccessList) {

        if (CollUtil.isEmpty(checkSuccessList)) {
            return;
        }

        List<CheckDiff> checkDiffList = checkSuccessList.stream().map(checkDiff -> checkDiff.setHandleState(CheckDiff.HANDLE_STATE_SUCCESS)).collect(Collectors.toList());

        boolean result = this.updateBatchById(checkDiffList);
        if (!result) {
            throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
        }
    }

    /** 更新差异单状态  挂账 -> 未处理 */
    public void updateHandleStateHangUp2Waiting(Date endDate) {
        CheckDiff updateCheckDiff = new CheckDiff();
        updateCheckDiff.setHandleState(CheckDiff.HANDLE_STATE_WAITING);

        this.update(updateCheckDiff, new LambdaUpdateWrapper<CheckDiff>()
                .eq(CheckDiff::getHandleState, CheckDiff.HANDLE_STATE_HANG_UP)
                .lt(CheckDiff::getBillDate, endDate)
        );
    }

    /** 用于重新对账，根据批次号，清空差异账单 */
    public void removeDiffByBatchNo(String batchNo) {
        this.remove(CheckDiff.gw().eq(CheckDiff::getBatchNo, batchNo));
    }

    /** 用于重新对账，根据批次号，清空渠道账单&&差异账单 */
    @Transactional
    public void removeDiffAndChannelBillByBatchNo(String batchNo) {
        // 清空渠道账单
        checkChannelBillService.remove(CheckChannelBill.gw().eq(CheckChannelBill::getBatchNo, batchNo));
        // 清空差异账单
        this.removeDiffByBatchNo(batchNo);
    }

    /** 差异订单忽略操作 */
    @Transactional
    public void ignoreDiff(Long id, String ignoreType, CheckDiff checkDiff, SysUser sysUser) {
        boolean result;

        if ("filter".equals(ignoreType)) {
            // 时间范围条件
            Date[] dateRange = checkDiff.buildQueryDateRange();

            if (StringUtils.isAllBlank(checkDiff.getIfCode(), checkDiff.getBatchNo(), checkDiff.getOrderId(), checkDiff.getDiffType())
                    && checkDiff.getHandleState() == null && dateRange[0] == null && dateRange[1] == null) {
                throw new BizException("请确定筛选条件");
            }

            // 按筛选条件  筛选出要更新的差异订单
            List<CheckDiff> list = this.list(CheckDiff.gw()
                    .eq(StringUtils.isNotBlank(checkDiff.getBatchNo()), CheckDiff::getBatchNo, checkDiff.getBatchNo())
                    .eq(StringUtils.isNotBlank(checkDiff.getIfCode()), CheckDiff::getIfCode, checkDiff.getIfCode())
                    .eq(StringUtils.isNotBlank(checkDiff.getDiffType()), CheckDiff::getDiffType, checkDiff.getDiffType())
                    .eq(checkDiff.getHandleState() != null, CheckDiff::getHandleState, checkDiff.getHandleState())
                    .eq(StringUtils.isNotBlank(checkDiff.getOrderId()), CheckDiff::getOrderId, checkDiff.getOrderId())
                    .ge(dateRange[0] != null, CheckDiff::getBillDate, dateRange[0])
                    .le(dateRange[1] != null, CheckDiff::getBillDate, dateRange[1])
                    .in(CheckDiff::getHandleState, Arrays.asList(CheckDiff.HANDLE_STATE_WAITING, CheckDiff.HANDLE_STATE_HANG_UP))
            );
            if (CollUtil.isEmpty(list)) {
                throw new BizException("当前筛选条件下，无可忽略的差异账单");
            }

            List<CheckDiff> updateList = list.stream().map(record -> {
                record.setHandleState(CheckDiff.HANDLE_STATE_IGNORE);
                record.setHandleUid(sysUser.getSysUserId());
                record.setHandleBy(sysUser.getRealname());

                return record;
            }).collect(Collectors.toList());

            // 批量更新
            result = this.updateBatchById(updateList);
            if (!result) {
                throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
            }

            // 更新当前差异账单所属批次未处理数量，数量为0时同步修改批次状态
            checkBatchService.updateUnHandleCountAndState4CheckDiff(updateList);
        }else {
            CheckDiff dbRecord = this.getById(id);
            if (dbRecord == null || (CheckDiff.HANDLE_STATE_WAITING == dbRecord.getHandleState() && CheckDiff.HANDLE_STATE_HANG_UP == dbRecord.getHandleState())) {
                throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
            }

            CheckDiff updateRecord = new CheckDiff();
            updateRecord.setId(id);
            updateRecord.setHandleState(CheckDiff.HANDLE_STATE_IGNORE);
            updateRecord.setHandleUid(sysUser.getSysUserId());
            updateRecord.setHandleBy(sysUser.getRealname());
            result = this.updateById(updateRecord);
            if (!result) {
                throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
            }

            // 当前差异账单所属批次未处理数量减一，数量为0时同步修改批次状态
            CheckBatch updateCheckBatch = new CheckBatch();
            updateCheckBatch.setUnHandleDiffCount(1);
            updateCheckBatch.setBatchNo(dbRecord.getBatchNo());
            checkBatchService.updateUnHandleCountAndState4CheckBatch(Arrays.asList(updateCheckBatch));
        }
    }

    /** 差异订单补单 */
    @Transactional
    public void reissue(CheckDiff dbRecord, SysUser sysUser) {

        CheckDiff updateRecord = new CheckDiff();
        updateRecord.setId(dbRecord.getId());
        updateRecord.setHandleState(CheckDiff.HANDLE_STATE_SUCCESS);
        updateRecord.setHandleUid(sysUser.getSysUserId());
        updateRecord.setHandleBy(sysUser.getRealname());
        boolean result = this.updateById(updateRecord);
        if (!result) {
            throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
        }

        // 当前差异账单所属批次未处理数量减一，数量为0时同步修改批次状态
        CheckBatch updateCheckBatch = new CheckBatch();
        updateCheckBatch.setUnHandleDiffCount(1);
        updateCheckBatch.setBatchNo(dbRecord.getBatchNo());
        checkBatchService.updateUnHandleCountAndState4CheckBatch(Arrays.asList(updateCheckBatch));


        // 更新订单状态
        if (StringUtils.isNotBlank(dbRecord.getOrderId())) {
            // 支付订单
            if (StringUtils.equals(dbRecord.getBillType(), CheckChannelBill.BILL_TYPE_PAY)) {
                PayOrder dbPayOrder = payOrderService.getById(dbRecord.getOrderId());
                if (dbPayOrder != null) {
                    if (dbPayOrder.getState() != PayOrder.STATE_ING && dbPayOrder.getState() != PayOrder.STATE_CLOSED) {
                        throw new BizException("仅支持同步支付中或超时关闭的订单！");
                    }

                    // 订单关闭 --> 支付中
                    if (dbPayOrder.getState() == PayOrder.STATE_CLOSED) {
                        payOrderService.updateClose2Ing(dbRecord.getOrderId());
                    }

                    // 支付中 --> 支付成功
                    result = payOrderService.updateIng2Success(dbRecord.getOrderId(), ChannelRetMsg.confirmSuccess(dbRecord.getChannelOrderNo()));
                    if (!result) {
                        throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
                    }
                }

            // 退款订单
            }else if (StringUtils.equals(dbRecord.getBillType(), CheckChannelBill.BILL_TYPE_REFUND)) {
                RefundOrder refundOrder = refundOrderService.getById(dbRecord.getOrderId());
                if (refundOrder != null) {
                    // 订单关闭 --> 退款中
                    refundOrderService.updateClose2Ing(dbRecord.getOrderId());
                    // 退款中 --> 退款成功
                    result = refundOrderService.updateIng2Success(dbRecord.getOrderId(), dbRecord.getChannelOrderNo());
                    if (!result) {
                        throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE);
                    }
                }
            }
        }
    }
}
