package com.jkcredit.invoice.hub.task;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jkcredit.invoice.hub.constant.CommonConstant;
import com.jkcredit.invoice.hub.enums.ApiResponseCodeEnum;
import com.jkcredit.invoice.hub.model.dto.apiCarFree.InvoiceResult;
import com.jkcredit.invoice.hub.model.dto.apiCarFree.InvoiceResultDto;
import com.jkcredit.invoice.hub.model.dto.needCharge.NeedChargeDto;
import com.jkcredit.invoice.hub.model.dto.searchInvoice.SearchInvoiceDto;
import com.jkcredit.invoice.hub.model.dto.searchInvoiceResult.SearchInvoiceResultDto;
import com.jkcredit.invoice.hub.model.dto.user.UserDto;
import com.jkcredit.invoice.hub.model.dto.userBalance.UserBalanceDto;
import com.jkcredit.invoice.hub.model.dto.userBalance.UserBalanceInvoiceDto;
import com.jkcredit.invoice.hub.model.po.carFreeCarrierBillStart.CarFreeCarrierBillStartPo;
import com.jkcredit.invoice.hub.model.po.searchInvoiceResult.SearchInvoiceResultPo;
import com.jkcredit.invoice.hub.puducer.ChargeProducer;
import com.jkcredit.invoice.hub.service.apiCarFree.ApiCarFreeService;
import com.jkcredit.invoice.hub.service.carFreeCarrierBillStart.CarFreeCarrierBillStartService;
import com.jkcredit.invoice.hub.service.needCharge.NeedChargeService;
import com.jkcredit.invoice.hub.service.realCharge.RealChargeService;
import com.jkcredit.invoice.hub.service.searchInvoice.SearchInvoiceService;
import com.jkcredit.invoice.hub.service.searchInvoiceResult.SearchInvoiceResultService;
import com.jkcredit.invoice.hub.service.user.UserService;
import com.jkcredit.invoice.hub.service.userBalance.UserBalanceService;
import com.jkcredit.invoice.hub.spi.rest.data.ApiResponseData;
import com.jkcredit.invoice.hub.util.BeanUtil;
import com.jkcredit.invoice.hub.util.CommonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

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

/**
 * @description:
 * @author: xusonglin
 * @create: 2020/1/18 15:49
 * @version: V1.0
 **/
@Component
@Slf4j
public class WayBillTask {
    @Autowired
    CarFreeCarrierBillStartService startService;
    @Autowired
    ApiCarFreeService carFreeService;
    @Autowired
    SearchInvoiceService searchInvoiceService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ChargeProducer chargeProducer;
    @Autowired
    UserBalanceService userBalanceService;
    @Autowired
    SearchInvoiceResultService searchInvoiceResultService;
    @Autowired
    NeedChargeService needChargeService;
    @Autowired
    RealChargeService realChargeService;
    @Autowired
    UserService userService;

    @Scheduled(cron = "0 1/3 * * * ?", zone = "Asia/Shanghai")
    public void realTimeWayBill() {
        // 查询实时订单，且状态为已结束和开票中
        // 调用运单查询发票接口
        // 解析结果
        // 如果result不为[]，则将结果入库
        // 根据返回transationID去重
        // 每一条放入消息队列，计费
        List<CarFreeCarrierBillStartPo> startPoList = startService.getRealTimeBills();
        charge(startPoList);

    }

    @Scheduled(cron = "0 1/9 * * * ?", zone = "Asia/Shanghai")
    public void historyWayBill() {
        // 查询实时订单，且状态为已结束和开票中
        // 调用运单查询发票接口
        // 解析结果
        // 如果result不为[]，则将结果入库
        // 根据返回transationID去重
        // 每一条放入消息队列，计费
        List<CarFreeCarrierBillStartPo> startPoList = startService.getHistoryBills();
        charge(startPoList);

    }

    private void charge(List<CarFreeCarrierBillStartPo> startPoList) {
        for (CarFreeCarrierBillStartPo po : startPoList) {
            // 封装查询参数
            JSONObject param = new JSONObject();
            param.put("num", po.getNum());

            // 接口调用
            ApiResponseData apiResponseData = carFreeService.waiBillNumFindInvoice(param);

            // 判断接口是否调用成功
            if (apiResponseData.getData().equals(CommonConstant.SUCCESS_CODE)
                    && apiResponseData.getCode().equals(ApiResponseCodeEnum.CODE_200.getValue())) {
                // 接口调用成功
                InvoiceResultDto invoiceResultDto = JSON.toJavaObject(JSON.parseObject(apiResponseData.getMsg()), InvoiceResultDto.class);
                List<InvoiceResult> newSearchInvoiceResultList;

                // 根据运单发票状态更新运单状态
                if (invoiceResultDto.getWaybillStatus().equals("3")) {
                    // 开票完成
                    startService.updateBillStartStatus(invoiceResultDto.getWaybillNum(), CommonConstant.STATUS_INVOICE_OVER);
                } else {
                    // 开票中
                    startService.updateBillStartStatus(invoiceResultDto.getWaybillNum(), CommonConstant.STATUS_MAKING_INVOICE);
                }
                if (invoiceResultDto.getResult() != null) {
                    // 判断运单查询发票返回共用信息在数据库中是否存在，不存在则存入
                    SearchInvoiceDto searchInvoiceDto = searchInvoiceService.getSearchInvoiceByNum(invoiceResultDto.getWaybillNum());
                    if (searchInvoiceDto == null) {
                        searchInvoiceService.saveSearchInvoice(invoiceResultDto);
                    }

                    if (invoiceResultDto.getResult().size() > 0) {
                        //去重列表
                        newSearchInvoiceResultList = invoiceResultDto.getResult().stream().collect(
                                Collectors.collectingAndThen(
                                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(InvoiceResult::getFee))), ArrayList::new));
                        //计费
                        newSearchInvoiceResultList.stream().forEach(t -> {
                            if (!redisTemplate.hasKey(CommonConstant.TRANSACTION_ID_KEY + t.getTransactionId())) {
                                UserBalanceDto userBalanceDto = userBalanceService.getUserBalance(po.getUserId());
                                UserBalanceInvoiceDto userBalanceInvoiceDto = new UserBalanceInvoiceDto();
                                BeanUtil.copyProperties(userBalanceInvoiceDto, userBalanceDto);
                                userBalanceInvoiceDto.setNum(t.getWaybillNum());
                                userBalanceInvoiceDto.setTransactionId(t.getTransactionId());
                                //发送到消息队列
                                chargeProducer.send(userBalanceInvoiceDto);
                                // 将需要计费数据插入数据库
                                UserDto userDto = userService.getUser(po.getUserId());
                                NeedChargeDto needChargeDto = new NeedChargeDto();
                                needChargeDto.setUserId(po.getUserId());
                                needChargeDto.setNum(t.getWaybillNum());
                                needChargeDto.setPrice(userDto.getPrice());
                                needChargeDto.setTransactionId(t.getTransactionId());
                                needChargeService.saveNeedCharge(needChargeDto);
                                log.warn("计费日志:{},计费用户id:{}", JSON.toJSONString(t), po.getUserId());
                            }
                        });
                    }
                    // 遍历发票集合
                    invoiceResultDto.getResult().stream().forEach(t -> {
                        if (!redisTemplate.hasKey(CommonConstant.NUM_FIND_INVOICE_KEY + t.getInvoiceNum() + "_" + t.getInvoiceCode())) {
                            SearchInvoiceResultDto dto = new SearchInvoiceResultDto();
                            BeanUtil.copyProperties(dto, t);
                            dto.setUserId(po.getUserId());
                            //插入发票信息
                            searchInvoiceResultService.saveSearchInvoiceResult(dto);
                            log.info("插入的发票信息:{}", JSON.toJSONString(t));
                            //存入redis发票信息
                            redisTemplate.opsForValue().set(CommonConstant.NUM_FIND_INVOICE_KEY + t.getInvoiceNum() + "_" + t.getInvoiceCode(), JSON.toJSONString(t));
                            //存入redis交易id
                            redisTemplate.opsForValue().set(CommonConstant.TRANSACTION_ID_KEY + t.getTransactionId(), t.getTransactionId());
                        }
                    });
                }
            } else {
                log.error("定时任务处理运单失败；失败原因：调用接口失败；时间：{}；运单编号：{}", CommonUtil.dateFormat(new Date()), po.getNum());
            }

        }
    }
}
