package com.usoft.fin.grpc.bl;

import com.alibaba.fastjson.JSON;
import com.google.protobuf.InvalidProtocolBufferException;
import com.usoft.bizcode.utils.BizCodeUtil;
import com.usoft.fin.grpc.api.entity.*;
import com.usoft.fin.grpc.api.protobuf.*;
import com.usoft.fin.grpc.bl.constants.BusinessType;
import com.usoft.fin.grpc.bl.constants.Status;
import com.usoft.fin.grpc.bl.constants.TableCode;
import com.usoft.fin.grpc.bl.entity.b2b.AcceptItem;
import com.usoft.fin.grpc.bl.entity.b2b.Order;
import com.usoft.fin.grpc.bl.entity.b2b.OrderItem;
import com.usoft.fin.grpc.dal.entity.*;
import com.usoft.fin.grpc.dal.mapper.*;
import com.usoft.fin.grpc.utils.DateUtils;
import com.usoft.fin.grpc.entity.PageInfo;
import com.usoft.fin.grpc.utils.FinanceGrpcRuntimeException;
import com.usoft.fin.grpc.utils.VerifyParamsUtil;
import com.usoft.mq.utils.RabbitSendService;
import com.usoft.protobuf.utils.ProtoBufUtil;
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 org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 提款 业务领域
 * @author liusw
 * @date 2018-08-28 11:13
 **/
@Service
public class DrawBl {

    @Autowired
    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    private DrawApplyMapper drawApplyMapper;

    @Autowired
    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    private CreditMapper creditMapper;

    @Autowired
    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    private CreditApplyMapper creditApplyMapper;

    @Autowired
    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    private RepayMapper repayMapper;

    @Autowired
    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    private RepayPlanMapper repayPlanMapper;

    @Autowired
    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    private DrawApplyUserfileMapper drawApplyUserfileMapper;

    @Autowired
    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    private FileTypeMapper fileTypeMapper;

    @Autowired
    private DrawApplyOrderAcceptMapper drawApplyOrderAcceptMapper;

    @Autowired
    private MessageBl messageBl;

    @Resource
    private RabbitSendService rabbitSendService;

    @Resource
    private B2BBl b2bBl;
    /**
     * 根据code获取提款申请记录
     *
     * @param request
     * @return
     */
    public GetDrawInfoResponse.Builder getDrawInfo(GetDrawInfoRequest request) throws InvalidProtocolBufferException {
        GetDrawInfoResponse.Builder response = GetDrawInfoResponse.newBuilder();
        VerifyParamsUtil.hasText(request.getCode(), "提款申请编号不能为空");
        DrawApply drawApply = drawApplyMapper.findByCode(request.getCode());
        if (drawApply == null) {
            throw new FinanceGrpcRuntimeException(-1, "提款申请记录有误");
        }
        // B2B订单查询
        List<DrawApplyOrderAccept> orderAccepts = drawApplyOrderAcceptMapper.findByDrawCode(request.getCode());
        List<OrderInfo> orderInfos = parseOrdeAcceptToOrderInfos(orderAccepts);

        DrawApplyInfo.Builder builder = DrawApplyInfo.newBuilder();
        builder = ProtoBufUtil.toProtoBuf(builder, drawApply);

        // 获取文件信息
        List<DrawApplyUserfile> drawApplyUserfiles = drawApplyUserfileMapper.findByDrawApplyCode(drawApply.getCode());
        // 文件类型 （只存在提款的分类）
        List<FileType> fileTypes = fileTypeMapper.findByProductCodeAndTypeCode(drawApply.getProductCode(), BusinessType.DRAW.getCode());

        // 组装数据
        Map<String, List<DrawApplyUserfileInfo>> userfileKV = new HashMap<>(16);
        for (DrawApplyUserfile drawApplyUserfile : drawApplyUserfiles) {
            // 如果没有，则添加
            if(!userfileKV.containsKey(drawApplyUserfile.getFileTypeCode())){
                userfileKV.put(drawApplyUserfile.getFileTypeCode(), new ArrayList<>());
            }
            DrawApplyUserfileInfo.Builder userfileBuilder = ProtoBufUtil.toProtoBuf(DrawApplyUserfileInfo.newBuilder(), drawApplyUserfile);

            userfileKV.get(drawApplyUserfile.getFileTypeCode()).add(userfileBuilder.build());
        }

        for (FileType fileType : fileTypes) {
            FileTypeDrawInfo.Builder fileTypeCreditInfo = FileTypeDrawInfo.newBuilder();

            FileTypeInfo.Builder fileTypeInfo = FileTypeInfo.newBuilder();
            fileTypeCreditInfo.setFileTypeInfo(ProtoBufUtil.toProtoBuf(fileTypeInfo, fileType));
            if (userfileKV.containsKey(fileType.getCode())) {
                fileTypeCreditInfo.addAllDrawApplyUserfileInfo(userfileKV.get(fileType.getCode()));
            }
            response.addFileTypeDrawInfo(fileTypeCreditInfo);
        }

        response.setDrawApplyInfo(builder);
        response.addAllOrderInfo(orderInfos);
        return response;
    }

    /**
     * 审核提款申请
     *
     * @param request
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public AuditDrawInfoResponse.Builder auditDrawInfo(AuditDrawInfoRequest request) throws InvalidProtocolBufferException {
        AuditDrawInfoResponse.Builder response = AuditDrawInfoResponse.newBuilder();
        VerifyParamsUtil.hasText(request.getCode(), "提款申请编号不能为空");
        // 查询当前提款编号是否存在
        DrawApply drawApply = drawApplyMapper.findByCode(request.getCode());
        if (drawApply == null) {
            throw new FinanceGrpcRuntimeException(-1, "提款申请记录有误");
        }
        drawApply.setAuditStatus((short) request.getAuditStatus());
        drawApply.setAuditDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        drawApplyMapper.updateByPrimaryKey(drawApply);
        return response;
    }

    /**
     * 打款提款申请
     *
     * @param request
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public DrawDrawInfoResponse.Builder drawDrawInfo(DrawDrawInfoRequest request) throws InvalidProtocolBufferException {
        DrawDrawInfoResponse.Builder response = DrawDrawInfoResponse.newBuilder();
        VerifyParamsUtil.hasText(request.getCode(), "提款申请编号不能为空");
        // 查询当前提款编号是否存在
        DrawApply drawApply = drawApplyMapper.findByCode(request.getCode());
        if (drawApply == null) {
            throw new FinanceGrpcRuntimeException(-1, "提款申请记录有误");
        }
        // TODO :只能打款已审核的
        if (drawApply.getAuditStatus() != Status.DRAW_APPLY_SUCCESS.value()) {
            throw new FinanceGrpcRuntimeException(-1, "提款记录未审核通过");
        }
        drawApply.setEndDate(request.getEndDate());
        drawApply.setStartDate(request.getStartDate());
        drawApply.setDrawStatus(Status.DRAW_APPLY_DRAW_SUCCESS.value());
        drawApplyMapper.updateByPrimaryKeySelective(drawApply);
        // 更新额度信息
        String creditCode = drawApply.getCreditCode();
        Credit credit = creditMapper.findByCode(creditCode);
        if (credit == null) {
            throw new FinanceGrpcRuntimeException(-1, "额度信息有误");
        }
        credit.setUsableAmount(BigDecimal.valueOf(request.getUsableAmount()));
        credit.setUsedAmount(BigDecimal.valueOf(request.getUsedAmount()));
        creditMapper.updateByPrimaryKeySelective(credit);
        // 生成还款
        Repay repay = repayMapper.findByDrawCode(drawApply.getCode());
        if (repay != null) {
            throw new FinanceGrpcRuntimeException(-1, "当前提款已生成还款信息");
        }
        repay = new Repay();
        repay.setCode(BizCodeUtil.genBizCode(TableCode.T_REPAY.getCode()));
        repay.setDrawCode(drawApply.getCode());
        // 还款列表
        repay.setProductCode(drawApply.getProductCode());
        repay.setEnuu(drawApply.getEnuu());
        repay.setStartDate(request.getStartDate());
        repay.setEndDate(request.getEndDate());
        repay.setDrawAmount(BigDecimal.valueOf(drawApply.getDrawAmount()));
        repay.setDrawMonthRate(drawApply.getMonthRate());

        // 还款计划保存
        List<RepayPlan> repayPlanList = repayPlanMapper.findByDrawCode(drawApply.getCode());
        if (!CollectionUtils.isEmpty(repayPlanList)) {
            throw new FinanceGrpcRuntimeException(-1, "还款计划已经生成");
        }
        List<RepayPlan> repayPlans = new ArrayList<>();
        // 判断传进来的还款计划是否为空
        if (CollectionUtils.isEmpty(request.getRepayPlanInfoList())) {
            throw new FinanceGrpcRuntimeException(-1, "还款计划为空");
        }
        for (RepayPlanInfo repayPlanInfo : request.getRepayPlanInfoList()) {
            RepayPlan repayPlan = new RepayPlan();
            repayPlan.setCode(BizCodeUtil.genBizCode(TableCode.T_REPAY_PLAN.getCode()));
            repayPlan.setRepayCode(repay.getCode());
            repayPlan.setRepayDate(repayPlanInfo.getRepayDate());
            repayPlan.setPeriodsNumber((short) repayPlanInfo.getPeriodsNumber());
            repayPlan.setShouldRepayInterest(BigDecimal.valueOf(repayPlanInfo.getShouldRepayInterest()));
            repayPlan.setShouldRepayPrincipal(BigDecimal.valueOf(repayPlanInfo.getShouldRepayPrincipal()));
            repayPlan.setShouldRepayTotal(BigDecimal.valueOf(repayPlanInfo.getShouldRepayTotal()));
            if (repayPlanInfo.getPeriodsNumber() == 1) {
                repay.setCurrentRepayMoment(BigDecimal.valueOf(repayPlanInfo.getShouldRepayTotal()));
                repay.setCurrentRepayTime(repayPlanInfo.getRepayDate());
                repay.setRepayPlanCode(repayPlan.getCode());
            }
            repayPlans.add(repayPlan);
        }
        // 保存还款和还款计划
        repayMapper.insert(repay);
        repayPlanMapper.insertAllSelective(repayPlans);
        messageBl.drawDrawMessage(request.getCode());
        return response;
    }

    @Transactional(rollbackFor = Exception.class)
    public SubmitDrawApplyFilesResponse.Builder submitDrawApplyFiles(SubmitDrawApplyFilesRequst request) throws InvalidProtocolBufferException {
        int enuu = request.getEnuu();
        SubmitDrawApplyFilesResponse.Builder response = SubmitDrawApplyFilesResponse.newBuilder();
        Credit credit = creditMapper.findByCode(request.getCreditCode());
        if (credit == null) {
            throw new FinanceGrpcRuntimeException(-1, "额度信息有误");
        }

        // 判断是否存在未打款的提款申请单
        boolean hasUnpaid = hasUnpaidDrawApply(request.getEnuu(), credit.getProductCode());
        if (hasUnpaid) {
            throw new FinanceGrpcRuntimeException(211, "提款申请正在审核中，请耐心等待");
        }

        // 生成提款记录
        DrawApply drawApply = new DrawApply();
        drawApply.setCode(BizCodeUtil.genBizCode(TableCode.T_DRAW_APPLY.getCode()));
        drawApply.setCreditCode(request.getCreditCode());
        drawApply.setCreditApplyCode(credit.getCreditApplyCode());
        drawApply.setProductCode(credit.getProductCode());
        drawApply.setEnuu(credit.getEnuu());
        drawApply.setSubmitDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        drawApply.setDrawAmount(request.getDrawAmount());
        drawApply.setMonthRate(credit.getRate());
        drawApply.setMaturity((short) request.getMaturity());

        // 保存文件
        List<SubmitDrawApplyUserFiles>  submitDrawApplyUserFiles = request.getSubmitDrawApplyUserFilesList();
        for (SubmitDrawApplyUserFiles file : submitDrawApplyUserFiles) {
            for (DrawApplyUserfileInfo drawApplyUserfileInfo : file.getDrawApplyUserfileInfoList()) {
                DrawApplyUserfile drawApplyUserfile = new DrawApplyUserfile();
                drawApplyUserfile.setCode(BizCodeUtil.genBizCode(TableCode.T_DRAW_APPLY_USER_FILE.getCode()));
                drawApplyUserfile.setDrawCode(drawApply.getCode());
                drawApplyUserfile.setFileTypeCode(file.getFileTypeCode());
                drawApplyUserfile.setNumber((short) drawApplyUserfileInfo.getNumber());
                drawApplyUserfile.setUrl(drawApplyUserfileInfo.getUrl());
                drawApplyUserfile.setName(drawApplyUserfileInfo.getName());
                drawApplyUserfile.setSize((long) drawApplyUserfileInfo.getSize());
                drawApplyUserfileMapper.insert(drawApplyUserfile);
            }
        }

        // 保存验收单信息
        String acceptIds = String.join(",", request.getOrderAcceptIdList());
        List<AcceptItem> acceptItems = b2bBl.getOrderAcceptByIds(enuu, acceptIds);
        double transferAmount = 0;
        for (AcceptItem acceptItem : acceptItems) {
            DrawApplyOrderAccept drawApplyOrderAccept = acceptItem.toDrawApplyOrderAccept();
            drawApplyOrderAccept.setDrawCode(drawApply.getCode());
            transferAmount += drawApplyOrderAccept.getAcceptAmount();
            drawApplyOrderAcceptMapper.insertSelective(drawApplyOrderAccept);
        }
        drawApply.setTransferAmount(BigDecimal.valueOf(transferAmount));
        drawApplyMapper.insertSelective(drawApply);
        response.setResponseHeader(ResponseHeader.newBuilder());

        // 发送mq给erp  TODO 是否跟随回滚
        rabbitSendService.sendMessage("finance_10046945","10046945", "1001", String.valueOf(BusinessType.DRAW.getCode()), drawApply.getCode());
        return response;
    }

    /**
     * 判断是否存在未打款的提款申请单
     * @param enuu 企业uu号
     * @param productCode 产品编号
     * @return 当有未打款的提款申请单并且处于审核中或者通过状态是返回true，其余返回false
     */
    private boolean hasUnpaidDrawApply(int enuu, String productCode) {
        List<DrawApply> drawApplies = drawApplyMapper.findByEnuuAndProductCode(productCode, enuu);
        if (!CollectionUtils.isEmpty(drawApplies)) {
            for (DrawApply drawApply : drawApplies) {
                // 未打款 && (审核中 || 通过)
                boolean flag = drawApply.getDrawStatus() == Status.DRAW_APPLY_DRAW_FAIL.value() && (drawApply.getAuditStatus() == Status.DRAW_APPLY_SUCCESS.value() || drawApply.getAuditStatus() == Status.DRAW_APPLY_WAITTING.value());
                if (flag) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 校验提款信息
     * @param request
     * @return 额度申请信息和当前企业的订单
     * @throws InvalidProtocolBufferException
     */
    public CheckDrawApplyInfoResponse.Builder checkDrawApplyInfo(CheckDrawApplyInfoRequest request) throws InvalidProtocolBufferException {
        /* 参数校验 */
        int enuu = request.getEnuu();
        String creditCode = request.getCreditCode();
        VerifyParamsUtil.notNull(creditCode, "额度申请编号不能为空");

        CheckDrawApplyInfoResponse.Builder response = CheckDrawApplyInfoResponse.newBuilder();

        /* 获取额度信息 */
        // 查询当前额度是否生效
        Credit credit = creditMapper.findByCode(creditCode);
        VerifyParamsUtil.notNull(credit, "额度信息有误");
        CreditInfo.Builder builder = CreditInfo.newBuilder();
        builder = ProtoBufUtil.toProtoBuf(builder, credit);
        if (!DateUtils.compareNow(credit.getStartDate(), credit.getEndDate())) {
            throw new FinanceGrpcRuntimeException(21, "额度非生效");
        }
        builder.setStatus(true);
        // 额度需大于0
        VerifyParamsUtil.isTrue(credit.getUsableAmount().compareTo(new BigDecimal(0)) > 0, "剩余可用额度不足");
        response.setCreditInfo(builder);

        // 判断是否存在未打款的提款申请单
        boolean hasUnpaid = hasUnpaidDrawApply(request.getEnuu(), credit.getProductCode());
        if (hasUnpaid) {
            throw new FinanceGrpcRuntimeException(211, "提款申请正在审核中，请耐心等待");
        }

        // 获取b2b订单
        List<Integer> acceptIds = drawApplyOrderAcceptMapper.findAcceptIdByEnuuAndProductCode(credit.getProductCode(), request.getEnuu());
        List<Order> orders = b2bBl.getOrder(enuu, StringUtils.join(acceptIds, ","));
        if (!CollectionUtils.isEmpty(orders)) {
            for (Order order : orders) {
                response.addOrderInfo(ProtoBufUtil.toProtoBuf(OrderInfo.newBuilder(), JSON.toJSONString(order)));
            }
        } else {
            throw new FinanceGrpcRuntimeException(-1, "当前无可提现的转让订单");
        }

        return response;
    }

    /**
     * 获取提款申请-上传资料项列表
     * @param request
     * @return
     * @throws InvalidProtocolBufferException
     */
    public GetDrawApplyFilesResponse.Builder getDrawApplyFiles(GetDrawApplyFilesRequest request) throws InvalidProtocolBufferException {
        GetDrawApplyFilesResponse.Builder response = GetDrawApplyFilesResponse.newBuilder();
        List<FileType> fileTypes = fileTypeMapper.findByProductCodeAndTypeCode(request.getProductCode(), BusinessType.DRAW.getCode());
        if (CollectionUtils.isEmpty(fileTypes)) {
            throw new FinanceGrpcRuntimeException(-1, "提款资料项缺失");
        }
        for (FileType fileType : fileTypes) {
            response.addFileTypeInfo(ProtoBufUtil.toProtoBuf(FileTypeInfo.newBuilder(), fileType));
        }
        return response;
    }

    /**
     * 获取提款申请列表
     * @param request
     * @return
     */
    public GetDrawApplyPagingInfoResponse.Builder getDrawApplyPagingInfo(GetDrawApplyPagingInfoRequest request) throws InvalidProtocolBufferException {
        GetDrawApplyPagingInfoResponse.Builder response = GetDrawApplyPagingInfoResponse.newBuilder();
        int number = request.getPageNumber();
        int size = request.getPageSize();
        int count = drawApplyMapper.countByEnuu(request.getEnuu());
        PageInfo pageInfo = new PageInfo(number, size, count);
        List<DrawApply> drawApplies = drawApplyMapper.findListByEnuu(pageInfo.getStartIndex(), size, request.getEnuu());
        response.setPagingInfo(ProtoBufUtil.toProtoBuf(PagingInfo.newBuilder(), pageInfo));
        for (DrawApply drawApply : drawApplies) {
            response.addDrawApplyInfo(ProtoBufUtil.toProtoBuf(DrawApplyInfo.newBuilder(), drawApply));
        }
        return response;
    }

    /**
     * 获取提款申请信息
     * @param request
     * @return
     * @throws InvalidProtocolBufferException
     */
    public GetDrawApplyInfoResponse.Builder getDrawApplyInfo(GetDrawApplyInfoRequest request) throws InvalidProtocolBufferException {
        GetDrawApplyInfoResponse.Builder response = GetDrawApplyInfoResponse.newBuilder();
        VerifyParamsUtil.hasText(request.getDrawApplyCode(), "提款申请编号不能为空");
        DrawApply drawApply = drawApplyMapper.findByCode(request.getDrawApplyCode());
        if (drawApply == null) {
            throw new FinanceGrpcRuntimeException(-1, "提款申请记录有误");
        }
        // B2B订单查询
        List<DrawApplyOrderAccept> orderAccepts = drawApplyOrderAcceptMapper.findByDrawCode(request.getDrawApplyCode());

        List<OrderInfo> orderInfos = parseOrdeAcceptToOrderInfos(orderAccepts);

        response.addAllOrderInfo(orderInfos);
        response.setDrawApplyInfo(ProtoBufUtil.toProtoBuf(DrawApplyInfo.newBuilder(), drawApply));
        return response;
    }

    private List<OrderInfo> parseOrdeAcceptToOrderInfos(List<DrawApplyOrderAccept> orderAccepts) throws InvalidProtocolBufferException {
        Map<Integer, OrderItem> orderDetailMap = new HashMap<>(16);
        Map<Integer, Order> orderMap = new HashMap<>(16);
        List<Order> orders = new ArrayList<>();
        for (DrawApplyOrderAccept drawApplyOrderAccept : orderAccepts) {
            // 转换采购订单
            AcceptItem accptBuilder = new AcceptItem();
            accptBuilder.setAcceptCode(drawApplyOrderAccept.getAcceptCode());
            accptBuilder.setAcceptDate(drawApplyOrderAccept.getAcceptDate());
            accptBuilder.setAcceptAmount(drawApplyOrderAccept.getAcceptAmount());
            accptBuilder.setIsCheck(drawApplyOrderAccept.getAcceptStatus());

            // 转换订单明细
            OrderItem detailBuilder = orderDetailMap.get(drawApplyOrderAccept.getOrderItemId());
            if (detailBuilder != null) {
                detailBuilder.getAcceptItems().add(accptBuilder);
                continue;
            }
            detailBuilder = new OrderItem();
            detailBuilder.setAcceptItems(new ArrayList<>());
            orderDetailMap.put(drawApplyOrderAccept.getOrderItemId(), detailBuilder);
            detailBuilder.getAcceptItems().add(accptBuilder);
            detailBuilder.setProductCode(drawApplyOrderAccept.getProductCode());
            detailBuilder.setProductTitle(drawApplyOrderAccept.getProductTitle());
            detailBuilder.setProductSpec(drawApplyOrderAccept.getProductSpec());
            detailBuilder.setProductCmpcode(drawApplyOrderAccept.getProductCmpcode());

            // 转换订单
            Order orderBuilder = orderMap.get(drawApplyOrderAccept.getOrderId());
            if (orderBuilder != null) {
                orderBuilder.getOrderItems().add(detailBuilder);
                continue;
            }
            orderBuilder = new Order();
            orderBuilder.setOrderItems(new ArrayList<>());
            orderMap.put(drawApplyOrderAccept.getOrderId(), orderBuilder);
            orderBuilder.getOrderItems().add(detailBuilder);
            orderBuilder.setOrderCode(drawApplyOrderAccept.getOrderCode());
            orderBuilder.setTotal(drawApplyOrderAccept.getOrderTotal());
            orderBuilder.setCustName(drawApplyOrderAccept.getCustName());
            orderBuilder.setDate(drawApplyOrderAccept.getOrderDate());
            orders.add(orderBuilder);
        }

        List<OrderInfo> orderInfos = new ArrayList<>();
        for (Order order : orders) {
            orderInfos.add(ProtoBufUtil.toProtoBuf(OrderInfo.newBuilder(), JSON.toJSONString(order)).build());
        }
        return orderInfos;
    }


}
