package com.tykj.dev.device.user.read.service.impl;

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.user.base.ret.MessageSelectVo;
import com.tykj.dev.device.user.read.repository.MessageDao;
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.read.subject.domin.Message;
import com.tykj.dev.device.user.read.subject.vo.MessageUserVo;
import com.tykj.dev.device.user.subject.dao.UserRecordDao;
import com.tykj.dev.device.user.subject.entity.UserRecord;
import com.tykj.dev.device.user.subject.service.UserRecordService;
import com.tykj.dev.device.user.util.UserUtils;
import com.tykj.dev.misc.exception.ApiException;
import com.tykj.dev.misc.utils.JacksonUtil;
import com.tykj.dev.misc.utils.StringSplitUtil;
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.stream.Collectors;

/**
 * @author dengdiyi
 */
@Service
public class MessageServiceImpl implements MessageService {

    @Autowired
    private MessageDao messageDao;

    @Autowired
    private UserUtils userUtils;

    @Autowired
    BlockChainUtil blockChainUtil;

    @Autowired
    UserRecordDao userRecordDao;

    @Autowired
    UserRecordService userRecordService;

    @Override
    public void add(MessageBto messageBto) {
        Message message = messageDao.save(messageBto.toDo());
        CompletableFuture.runAsync(()->{
            Message message1 = get(message.getId());
            BcHash bcText = blockChainUtil.sendHash(1000, JacksonUtil.toJSon(message1));
            String recordId = bcText.getData().getRecordID();
            message1.setRecordId(recordId);
            messageDao.save(message1);
        }, TaskBeanConfig.getThreadPoolTaskScheduler());
    }

    @Override
    @Async
    public void sendHash(Message message) {
        BcHash bcText = blockChainUtil.sendHash(1000, JacksonUtil.toJSon(message));
        String recordId = bcText.getData().getRecordID();
        message.setRecordId(recordId);
        messageDao.save(message);
    }

    @Override
    public Message update(Message message) {
        return messageDao.save(message);
    }

    @Override
    public Message get(Integer id) {
        Optional<Message> message = messageDao.findById(id);
        if (message.isPresent()){
            return message.get();
        }
        else {
            throw  new ApiException("Id不存在");
        }
    }

    @Override
    public void delete(Integer id) {
        messageDao.deleteById(id);
    }

    @Override
    public List<MessageUserVo> getList() {
        Integer userId = userUtils.getCurrentUserId();
        List<MessageUserVo> messageUserVos = messageDao.findAll().stream()
                .map(Message::parse2Bto)
                .filter(messageBto -> messageBto.getInvolveUserIdList().contains(userId)&&!messageBto.getCompleteUserIdList().contains(userId))
                .map(MessageBto::toVo)
                .sorted(Comparator.comparing(MessageUserVo::getCreateTime,Comparator.nullsLast(Date::compareTo)).reversed())
                .collect(Collectors.toList());
        List<Integer> ids = messageUserVos.stream().map(MessageUserVo::getId).collect(Collectors.toList());
        List<UserRecord> userRecords = userRecordDao.findAllByUserId(userId);
        if (userRecords.isEmpty()) {
            UserRecord userRecord2 = new UserRecord();
            userRecord2.setUserId(userId);
            userRecord2.setReadIds(StringSplitUtil.idListToString(ids));
            userRecord2.setNewReadIds(userRecord2.getReadIds());
            userRecordService.save(userRecord2);
        } else {
            UserRecord userRecord = userRecords.get(0);
            if (userRecord.getReadIds() == null) {
                //更新阅知id
                userRecord.setReadIds(StringSplitUtil.idListToString(ids));
                userRecord.setNewReadIds(userRecord.getReadIds());
                userRecordService.save(userRecord);
            } else {
                List<Integer> integerList = StringSplitUtil.userIdSplit(userRecord.getReadIds());
                //更新阅知id
                userRecord.setReadIds(StringSplitUtil.idListToString(ids));
                //和上一次比新增的id
                ids.removeAll(integerList);
                userRecord.setNewReadIds(StringSplitUtil.idListToString(ids));
                userRecordService.save(userRecord);
            }
        }
        //设置新增的阅知字段
        messageUserVos.forEach(messageUserVo -> {
            if (ids.contains(messageUserVo.getId())){
                messageUserVo.setIsNew(1);
            }
        });
        return messageUserVos;
    }

    @Override
    public List<MessageUserVo> getNewList() {
        List<MessageUserVo> messageUserVos = new ArrayList<>();
        Integer userId = userUtils.getCurrentUserId();
        List<UserRecord> userRecords = userRecordDao.findAllByUserId(userId);
        if (userRecords.isEmpty()){
            return messageUserVos;
        }
        else {
            UserRecord userRecord = userRecords.get(0);
            List<Integer> newTaskIds = StringSplitUtil.userIdSplit(userRecord.getNewReadIds());
            //筛选出新id的阅知
            messageUserVos = messageDao.findAll().stream()
                    .map(Message::parse2Bto)
                    .filter(messageBto -> messageBto.getInvolveUserIdList().contains(userId) &&
                            !messageBto.getCompleteUserIdList().contains(userId) && newTaskIds.contains(messageBto.getId()))
                    .map(MessageBto::toVo)
                    .sorted(Comparator.comparing(MessageUserVo::getCreateTime, Comparator.nullsLast(Date::compareTo)).reversed())
                    .collect(Collectors.toList());
            return messageUserVos;
        }
    }

    @Override
    public List<MessageUserVo> getAllList(MessageSelectVo messageSelectVo) {
        Integer userId = userUtils.getCurrentUserId();
        Boolean hasYear = messageSelectVo.getYear()!=null;
        Boolean hasBusinessType = messageSelectVo.getBusinessType()!=null;
        return messageDao.findAll().stream()
                .map(Message::parse2Bto)
                .filter(messageBto -> messageBto.getInvolveUserIdList().contains(userId)
                        &&(!hasBusinessType||messageBto.getBusinessType().equals(messageSelectVo.getBusinessType()))
                        &&(!hasYear||messageBto.getCreateTime().getYear()==messageSelectVo.getYear()-1900))
                .map(MessageBto::toVo)
                .filter(messageUserVo -> messageUserVo.getIsRead().equals(messageSelectVo.getIsRead()))
                .sorted(Comparator.comparing(MessageUserVo::getCreateTime,Comparator.nullsLast(Date::compareTo)).reversed())
                .collect(Collectors.toList());
    }

    @Override
    public List<MessageBto> getBtoList() {
        Integer userId = userUtils.getCurrentUserId();
        return messageDao.findAll().stream()
                .map(Message::parse2Bto)
                .filter(messageBto -> messageBto.getInvolveUserIdList().contains(userId)&&!messageBto.getCompleteUserIdList().contains(userId))
                .collect(Collectors.toList());
    }

    /**
     * @param messageId 阅知信息id
     */
    @Override
    public Message read(Integer messageId) {
        Integer userId = userUtils.getCurrentUserId();
        MessageBto messageBto = get(messageId).parse2Bto();
        List<Integer> userIds = messageBto.getUserReadDetailList();
        userIds.add(userId);
        messageBto.setUserReadDetailList(userIds);
        List<Integer> userIds2 = messageBto.getCompleteUserIdList();
        userIds2.add(userId);
        messageBto.setCompleteUserIdList(userIds2);
        return messageDao.save(messageBto.toDo());
    }

    /**
     * @param messageId 阅知信息id
     *                  完成该阅知信息
     */
    @Override
    public Message complete(Integer messageId) {
        Integer userId = userUtils.getCurrentUserId();
        MessageBto messageBto = get(messageId).parse2Bto();
        List<Integer> userIds = messageBto.getCompleteUserIdList();
        userIds.add(userId);
        messageBto.setCompleteUserIdList(userIds);
        return messageDao.save(messageBto.toDo());
    }
}
