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.*;
import com.tykj.dev.device.library.service.DeviceLibraryCacheService;
import com.tykj.dev.device.library.service.DeviceLibraryService;
import com.tykj.dev.device.library.service.impl.CacheLibraryServiceImpl;
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 com.tykj.dev.misc.utils.StringSplitUtil;
import com.tykj.dev.misc.utils.StringUtils;
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;

    @Autowired
    private DeviceLibraryCacheService deviceLibraryCacheService;

    @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);
                }
            }
        }
    }

    @Override
    public List<StringBuffer> checkNumAndSeqNumber(List<ApplyTaskDeviceCheckVo> applyTaskDeviceCheckVos) {
        List<StringBuffer> stringBufferList = new ArrayList<>();
        applyTaskDeviceCheckVos.forEach(applyTaskDeviceCheckVo -> {
            StringBuffer stringBuffer = new StringBuffer();
            //先判断数量是否一致
            //入库数量
            Integer storageCount = applyTaskDeviceCheckVo.getStorageCount();
            //批复数量
            Integer replyNum = applyTaskDeviceCheckVo.getReplyNum();
            //试用装备数量
            Integer tryOutNum = applyTaskDeviceCheckVo.getTryOutNum();

            stringBuffer.append("序号为").append(applyTaskDeviceCheckVo.getI()+1).append(":");
            if (replyNum<tryOutNum){
                //提示  批复数量不能小于试用数量
                stringBuffer.append("批复数量不能小于试用数量").append(",");
            }
            if (replyNum>storageCount){
                //提示 批复数量不能大于申请数量
                stringBuffer.append("批复数量不能大于申请数量").append(",");
            }
            //获取序列号区间
            String seqNumInter = applyTaskDeviceCheckVo.getSeqNumInter();
            if (seqNumInter != null){
                //然后进行拆分
                //输入序列号的区间
                List<String> inputSeqs = DeviceSeqUtil.selectDeviceSeqs(seqNumInter);
                if (!replyNum.equals(inputSeqs.size())){
                    //提示  批复数量跟输入区间不一致
                    stringBuffer.append("批复数量与序列号区间不一致");
                }
                //查询所有的序列号 检验是否重复
//                List<String> allSeqList = deviceLibraryCacheService.getAllDeviceLibraryList().stream()
//                        .map(DeviceLibrary::getSeqNumber).collect(Collectors.toList());
//                allSeqList.retainAll(inputSeqs);
//                if (allSeqList.size()>0){
//                    //说明有重复的序列号
//                    stringBuffer.append("序列号").append(allSeqList).append("已存在");
//                }
            }

            stringBufferList.add(stringBuffer);
        });

        return stringBufferList;
    }

    @Override
    public List<StringBuffer> checkNumAndSeqNumberForOtherApply(List<OtherApplyTaskDeviceCheckVo> otherApplyTaskDeviceCheckVos) {

        List<StringBuffer> stringBufferList = new ArrayList<>();
        //在库序列号
        List<String> seqList = deviceLibraryCacheService.getAllDeviceLibraryList().stream()
                .map(DeviceLibrary::getSeqNumber).collect(Collectors.toList());

        otherApplyTaskDeviceCheckVos.forEach(otherApplyTaskDeviceCheckVo -> {
            StringBuffer stringBuffer = new StringBuffer();
            //获取申请数量
            Integer applyNum = otherApplyTaskDeviceCheckVo.getApplyNum();
            //获取序列号区间
            String seqNumInter = otherApplyTaskDeviceCheckVo.getSeqNumInter();
            //输入序列号的区间
            List<String> inputSeqs = DeviceSeqUtil.selectDeviceSeqs(seqNumInter);
            stringBuffer.append("序号为").append(otherApplyTaskDeviceCheckVo.getI()+1).append(":");
            if (applyNum != inputSeqs.size()){
                stringBuffer.append("申请数量和序列号不一致").append(",");
            }
            //取交集
            inputSeqs.forEach(s -> {
                if (!seqList.contains(s)){
                    //不在库  需要提示
                    stringBuffer.append("该").append(s).append("序列号不在库,请更换序列号");
                }
            });
            stringBufferList.add(stringBuffer);
        });
        return stringBufferList;
    }

    @Override
    public List<String> removeFromSeqList(RemoveFromSeqListVo removeFromSeqListVo) {
        //对区间进行拆分
        String seqNumberList = removeFromSeqListVo.getSeqNumberList();
        //对序列号区间进行拆分
        List<String> seqs = DeviceSeqUtil.selectDeviceSeqs(seqNumberList);
        seqs.removeAll(removeFromSeqListVo.getRemoveSeqNumberList());
        //对原来的集合先进行排序
        seqs.sort(Comparator.comparing(String::toString));
        return DeviceSeqUtil.getContinuousSeqs(seqs);
    }

    @Override
    public ApplyRemoveSeqVo removeSameSeq(RemoveSameSeqVo removeSameSeqVo) {
        ApplyRemoveSeqVo applyRemoveSeqVo = new ApplyRemoveSeqVo();
        String seqNumberList = removeSameSeqVo.getSeqNumberList();
        List<String> selectDeviceSeqs = DeviceSeqUtil.selectDeviceSeqs(seqNumberList);
        if (selectDeviceSeqs.size()>0){
            List<String> removeSameSeq = removeSameSeqVo.getRemoveSameSeq();
            if (removeSameSeq.size()>0){
                selectDeviceSeqs.removeAll(removeSameSeq);
            }
        }
        List<String> continuousSeqs = DeviceSeqUtil.getContinuousSeqs(selectDeviceSeqs);
        applyRemoveSeqVo.setSeqList(continuousSeqs);
        applyRemoveSeqVo.setCount(selectDeviceSeqs.size());
        return applyRemoveSeqVo;
    }
}
