package com.tykj.dev.device.apply.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.tykj.dev.blockcha.subject.entity.BcHash;
import com.tykj.dev.blockcha.subject.service.BlockChainUtil;
import com.tykj.dev.config.TaskBeanConfig;
import com.tykj.dev.device.apply.repository.DeviceApplyBillDao;
import com.tykj.dev.device.apply.service.DeviceApplyBillService;
import com.tykj.dev.device.apply.subject.domin.DeviceApplyBill;
import com.tykj.dev.device.apply.subject.vo.ReplyVo;
import com.tykj.dev.device.library.service.DeviceLibraryService;
import com.tykj.dev.device.library.subject.domin.DeviceLibrary;
import com.tykj.dev.device.library.subject.vo.ScriptSaveVo;
import com.tykj.dev.device.task.repository.TaskDao;
import com.tykj.dev.device.task.service.TaskService;
import com.tykj.dev.device.task.subject.bto.TaskBto;
import com.tykj.dev.device.task.subject.domin.Task;
import com.tykj.dev.device.user.read.service.MessageService;
import com.tykj.dev.device.user.read.subject.bto.MessageBto;
import com.tykj.dev.device.user.subject.service.UserPublicService;
import com.tykj.dev.device.user.util.UserUtils;
import com.tykj.dev.misc.base.StatusEnum;
import com.tykj.dev.misc.utils.DeviceSeqUtil;
import com.tykj.dev.misc.utils.JacksonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;

/**
 * @author dengdiyi
 */
@Service
public class DeviceApplyBillServiceImpl implements DeviceApplyBillService {

    @Autowired
    private DeviceApplyBillDao deviceApplyBillDao;

    @Autowired
    private BlockChainUtil blockChainUtil;

    @Autowired
    private TaskDao taskDao;

    @Autowired
    private DeviceLibraryService deviceLibraryService;

    @Autowired
    private MessageService messageService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private UserPublicService userPublicService;

    @Autowired
    private UserUtils userUtils;

    @Override
    public DeviceApplyBill addEntity(DeviceApplyBill deviceApplyBillEntity) {
        DeviceApplyBill deviceApplyBill = deviceApplyBillDao.save(deviceApplyBillEntity);
        CompletableFuture.runAsync(()->{
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            DeviceApplyBill deviceApplyBill1 = getOne(deviceApplyBill.getId());
            BcHash bcText = blockChainUtil.sendHash(1000, JacksonUtil.toJSon(deviceApplyBill1));
            String recordId = bcText.getData().getRecordID();
            deviceApplyBill1.setRecordId(recordId);
            deviceApplyBillDao.save(deviceApplyBill1);
        }, TaskBeanConfig.getThreadPoolTaskScheduler());
        return deviceApplyBill;
    }

    /**
     * @param deviceApplyBills 异步上链
     */
    @Override
    @Async
    public void sendHash(List<DeviceApplyBill> deviceApplyBills) {
        deviceApplyBills.forEach(deviceApplyBill -> {
            BcHash bcText = blockChainUtil.sendHash(1000, JacksonUtil.toJSon(deviceApplyBill));
            String recordId = bcText.getData().getRecordID();
            deviceApplyBill.setRecordId(recordId);
            update(deviceApplyBill);
        });
    }

    @Override
    public DeviceApplyBill update(DeviceApplyBill deviceApplyBillEntity) {
        DeviceApplyBill deviceApplyBill = deviceApplyBillDao.save(deviceApplyBillEntity);
        CompletableFuture.runAsync(()->blockChainUtil.appendHash(JacksonUtil.toJSon(deviceApplyBill),deviceApplyBill.getRecordId()),TaskBeanConfig.getThreadPoolTaskScheduler());
        return deviceApplyBill;
    }

    @Override
    public DeviceApplyBill getOne(Integer id) {
        Optional<DeviceApplyBill> deviceApplyBillEntity = deviceApplyBillDao.findById(id);
        return deviceApplyBillEntity.orElse(null);
    }

    @Override
    public void updateCompleteNum(Integer applyType,List<ScriptSaveVo> scriptSaveVos) {
        //筛选出所有申请完成后待执行的任务
        Map<Integer, Task> taskMap = taskDao.findAllByBusinessTypeAndBillStatus(9, StatusEnum.WAIT_CONFIRM_APPLY_DEVICE.id).stream().collect(Collectors.toMap(Task::getId, Function.identity()));
        //所有申请单Id的map
        Map<Integer, DeviceApplyBill> billMap = deviceApplyBillDao.findAll().stream().collect(Collectors.toMap(DeviceApplyBill::getId,Function.identity()));
        //所有装备序列号map
        Map<String, DeviceLibrary> seqMap = deviceLibraryService.getAllDeviceSeqMap();
        //根据序列号区间找到所有装备
        List<DeviceLibrary> deviceLibraries = new ArrayList<>();
        for (ScriptSaveVo s:scriptSaveVos) {
            if (s.getSeqNumber()!=null){
                DeviceSeqUtil.selectDeviceSeqs(s.getSeqNumber()).forEach(s1 -> deviceLibraries.add(seqMap.get(s1)));
            }
        }
        //taskId为主键，对应装备集合为值的map
        Map<Integer,List<DeviceLibrary>> taskIdMap= deviceLibraries.stream().filter(deviceLibrary -> deviceLibrary.getApplyTaskId()!=null).collect(groupingBy(DeviceLibrary::getApplyTaskId));
        //根据taskIdMap遍历
        for (Integer taskId:taskIdMap.keySet()) {
            //将该task涉及装备按列装id分组
            Map<Integer,List<DeviceLibrary>> map = taskIdMap.get(taskId).stream().collect(groupingBy(DeviceLibrary::getPackingId));
            TaskBto taskBto = taskMap.get(taskId).parse2Bto();
            DeviceApplyBill deviceApplyBill = billMap.get(taskBto.getBillId());
            //该任务是否完成
            Boolean isComplete = true;
            if (deviceApplyBill.getReplyVos()!=null&&!"".equals(deviceApplyBill.getReplyVos())) {
                //转换json
                List<ReplyVo> replyVos = JacksonUtil.readValue(deviceApplyBill.getReplyVos(), new TypeReference<List<ReplyVo>>() {
                });
                //存放未完成数量装备
                List<DeviceLibrary> deviceLibraryList = new ArrayList<>();
                if (replyVos != null) {
                    for(ReplyVo r:replyVos){
                        if (map.get(r.getId())!=null){
                            //完成数量增加
                            r.setCompleteCount(r.getCompleteCount()+map.get(r.getId()).size());
                            //如果完成数量不等于申请数量
                            if (!r.getCompleteCount().equals(r.getNum())){
                                isComplete = false;
                                List<String> seqs = DeviceSeqUtil.selectDeviceSeqs(r.getSeqInterval());
                                //移除已完成数量装备序列号
                                seqs.removeAll(map.get(r.getId()).stream().map(DeviceLibrary::getSeqNumber).collect(Collectors.toList()));
                                //将未完成的装备添加到集合
                                seqs.forEach(s -> deviceLibraryList.add(seqMap.get(s)));
                            }
                        }
                    }
                    if (!isComplete){
                        //存放所有未完成装备生命状态
                        Set<Integer> lifeStatus = deviceLibraryList.stream().map(DeviceLibrary::getLifeStatus).collect(Collectors.toSet());
                        //存放所有完成的状态
                        Set<Integer> integers = new HashSet<>();
                        integers.add(11);
                        if (applyType==2) {
                            integers.add(15);
                            integers.add(12);
                            integers.add(16);
                        }
                        if (applyType==3){
                            integers.add(17);
                            integers.add(5);
                            integers.add(18);
                        }
                        if (applyType==4){
                            integers.add(19);
                            integers.add(10);
                            integers.add(20);
                        }
                        //判断剩下未完成的装备是否生命状态算完成
                        if (integers.containsAll(lifeStatus)){
                            isComplete = true;
                        }
                    }
                    //如果已完成
                    if (isComplete){
                        //业务办结
                        taskService.addInvolveUser(taskBto,userUtils.getCurrentUserId());
                        taskService.moveToEnd(taskBto);
                        //发送阅知信息
                        MessageBto messageBto = new MessageBto();
                        messageBto.setContent("业务办结");
                        messageBto.setTaskId(taskBto.getId());
                        messageBto.setIsHighLight(0);
                        messageBto.setInvolveUserIdList(userPublicService.findOtherUser(userUtils.getCurrentUserId()));
                        messageBto.setBusinessType(taskBto.getBusinessType());
                        messageService.add(messageBto);
                    }
                    //更新账单replyVos
                    deviceApplyBill.setReplyVos(JacksonUtil.toJSon(replyVos));
                    update(deviceApplyBill);
                }
            }
        }
    }
}
