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

import com.github.wenhao.jpa.PredicateBuilder;
import com.github.wenhao.jpa.Specifications;
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.library.service.DeviceLibraryService;
import com.tykj.dev.device.library.service.DeviceLogService;
import com.tykj.dev.device.library.subject.Dto.DeviceLogDto;
import com.tykj.dev.device.library.subject.domin.DeviceLibrary;
import com.tykj.dev.device.matching.repository.MatchingDeviceLibraryDao;
import com.tykj.dev.device.matching.service.MatchingDeviceLibraryService;
import com.tykj.dev.device.matching.subject.domin.MatchingDeviceLibrary;
import com.tykj.dev.device.matching.subject.vo.MatchingDeviceSelectVo;
import com.tykj.dev.device.matching.subject.vo.RelationDeviceVo;
import com.tykj.dev.device.user.subject.service.UserPublicService;
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.PageUtil;
import com.tykj.dev.misc.utils.ResultUtil;
import com.tykj.dev.rfid.entity.vo.PrintVo;
import com.tykj.dev.rfid.entity.vo.RfidPrintVo;
import com.tykj.dev.rfid.service.RfidService;
import com.tykj.dev.rfid.service.impl.RfidServiceImpl;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;

import javax.persistence.Transient;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author dengdiyi
 */
@Service
public class MatchingDeviceLibraryServiceImpl implements MatchingDeviceLibraryService {

    @Autowired
    private MatchingDeviceLibraryDao matchingDeviceLibraryDao;

    @Autowired
    private UserUtils userUtils;

    @Autowired
    private UserPublicService userPublicService;

    @Autowired
    private BlockChainUtil blockChainUtil;

    @Autowired
    private DeviceLogService deviceLogService;

    @Autowired
    private RfidService rfidService;

    @Override
    public MatchingDeviceLibrary addEntity(MatchingDeviceLibrary matchingDeviceLibraryEntity) {
        MatchingDeviceLibrary matchingDeviceLibrary = matchingDeviceLibraryDao.save(matchingDeviceLibraryEntity);
        CompletableFuture.runAsync(()->{
            MatchingDeviceLibrary matchingDeviceLibrary1 = getOne(matchingDeviceLibrary.getId());
            BcHash bcText = blockChainUtil.sendHash(1000, JacksonUtil.toJSon(matchingDeviceLibrary1));
            String recordId = bcText.getData().getRecordID();
            matchingDeviceLibrary1.setRecordId(recordId);
            matchingDeviceLibraryDao.save(matchingDeviceLibrary1);
        }, TaskBeanConfig.getThreadPoolTaskScheduler());
        return matchingDeviceLibrary;
    }

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

    @Override
    public MatchingDeviceLibrary getOne(Integer id) {
        Optional<MatchingDeviceLibrary> matchingDeviceLibraryEntity = matchingDeviceLibraryDao.findById(id);
        if (matchingDeviceLibraryEntity.isPresent()){
            return matchingDeviceLibraryEntity.get().setConfigName();
        }
        else {
            throw new ApiException("id不存在");
        }
    }

    @Override
    public MatchingDeviceLibrary update(MatchingDeviceLibrary matchingDeviceLibraryEntity) {
//        blockChainUtil.appendHash(JacksonUtil.toJSon(matchingDeviceLibraryEntity),matchingDeviceLibraryEntity.getRecordId());
        return matchingDeviceLibraryDao.save(matchingDeviceLibraryEntity);
    }

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

    @Override
    public Page<MatchingDeviceLibrary> getPage(MatchingDeviceSelectVo matchingDeviceSelectVo, Pageable pageable) {
        PredicateBuilder<MatchingDeviceLibrary> predicateBuilder = getPredicate(matchingDeviceSelectVo);
        Integer selectUnitId = matchingDeviceSelectVo.getUnitId();
        Integer selectAreaId = matchingDeviceSelectVo.getAreaId();
        if (selectAreaId == null) {
            //如果areaId和unitId都传Null,返回当前单位的配套设备
            if (selectUnitId == null) {
//                predicateBuilder.eq("createUnit", userUtils.getCurrentUserUnitName());
                return matchingDeviceLibraryDao.findAll(predicateBuilder.build(), matchingDeviceSelectVo.getPageable());
            }
            //如果areaId为Null,unitId不为null,返回对应单位的配套设备
            else {
                String unitName = userPublicService.findByUnitsToname(selectUnitId);
                predicateBuilder.eq("createUnit", unitName);
                return matchingDeviceLibraryDao.findAll(predicateBuilder.build(), matchingDeviceSelectVo.getPageable());
            }
        }
        //areaId不为null,返回该区域下所有单位的配套设备
        else {
            //获取区域等级
            Integer selectLevel = userPublicService.getArea(selectAreaId).getType();
            //获取区域下所有单位名称
//            List<String> units = userPublicService.findAllUnitNameByAreaId(selectAreaId);
            List<Integer> units = userPublicService.findAllUnitIdByAreaId(selectAreaId);
            //如果是市或县，筛选出创建单位在units中的设备
            if (selectLevel == 3 || selectLevel == 2) {
//                List<MatchingDeviceLibrary> resultList = matchingDeviceLibraryDao.findAll(getPredicate(matchingDeviceSelectVo).build())
//                        .stream()
//                        .filter(matchingDeviceLibraryEntity -> units.contains(matchingDeviceLibraryEntity.getCreateUnit()))
//                        .collect(Collectors.toList());
                List<MatchingDeviceLibrary> resultList = matchingDeviceLibraryDao.findAll(getPredicate(matchingDeviceSelectVo).build())
                        .stream()
                        .filter(matchingDeviceLibraryEntity -> units.contains(matchingDeviceLibraryEntity.getCreateUnitId()))
                        .collect(Collectors.toList());
//                List<MatchingDeviceLibrary> resultList = matchingDeviceLibraryDao.findAll().stream()
//                        .filter(matchingDeviceLibraryEntity -> units.contains(matchingDeviceLibraryEntity.getCreateUnit()))
//                        .collect(Collectors.toList());
                return PageUtil.getPerPage(matchingDeviceSelectVo.getPage(), matchingDeviceSelectVo.getSize(), resultList, pageable);
            }
            //如果是省，直接返回全部设备
            if (selectLevel == 1) {
//                List<MatchingDeviceLibrary> resultList = matchingDeviceLibraryDao.findAll();
                List<MatchingDeviceLibrary> resultList = matchingDeviceLibraryDao.findAll(getPredicate(matchingDeviceSelectVo).build());
                return PageUtil.getPerPage(matchingDeviceSelectVo.getPage(), matchingDeviceSelectVo.getSize(), resultList, pageable);
            } else {
                throw new ApiException(ResultUtil.failed("单位等级只能为1,2,3"));
            }
        }
    }

    @Override
    public List<MatchingDeviceLibrary> getMatchingDevicePage(MatchingDeviceSelectVo matchingDeviceSelectVo) {
        PredicateBuilder<MatchingDeviceLibrary> predicateBuilder = getPredicate(matchingDeviceSelectVo);
        Integer selectUnitId = matchingDeviceSelectVo.getUnitId();
        Integer selectAreaId = matchingDeviceSelectVo.getAreaId();
        if (selectAreaId == null) {
            //如果areaId和unitId都传Null,返回当前单位的配套设备
            if (selectUnitId == null) {
//                predicateBuilder.eq("createUnit", userUtils.getCurrentUserUnitName());
                return matchingDeviceLibraryDao.findAll(predicateBuilder.build());
            }
            //如果areaId为Null,unitId不为null,返回对应单位的配套设备
            else {
                String unitName = userPublicService.findByUnitsToname(selectUnitId);
                predicateBuilder.eq("createUnit", unitName);
                return matchingDeviceLibraryDao.findAll(predicateBuilder.build());
            }
        }
        //areaId不为null,返回该区域下所有单位的配套设备
        else {
            //获取区域等级
            Integer selectLevel = userPublicService.getArea(selectAreaId).getType();
            //获取区域下所有单位名称
//            List<String> units = userPublicService.findAllUnitNameByAreaId(selectAreaId);
            List<Integer> units = userPublicService.findAllUnitIdByAreaId(selectAreaId);
            //如果是市或县，筛选出创建单位在units中的设备
            if (selectLevel == 3 || selectLevel == 2) {
//                List<MatchingDeviceLibrary> resultList = matchingDeviceLibraryDao.findAll(getPredicate(matchingDeviceSelectVo).build())
//                        .stream()
//                        .filter(matchingDeviceLibraryEntity -> units.contains(matchingDeviceLibraryEntity.getCreateUnit()))
//                        .collect(Collectors.toList());
                List<MatchingDeviceLibrary> resultList = matchingDeviceLibraryDao.findAll(getPredicate(matchingDeviceSelectVo).build())
                        .stream()
                        .filter(matchingDeviceLibraryEntity -> units.contains(matchingDeviceLibraryEntity.getCreateUnitId()))
                        .collect(Collectors.toList());
//                List<MatchingDeviceLibrary> resultList = matchingDeviceLibraryDao.findAll().stream()
//                        .filter(matchingDeviceLibraryEntity -> units.contains(matchingDeviceLibraryEntity.getCreateUnit()))
//                        .collect(Collectors.toList());
                return  resultList;
            }
            //如果是省，直接返回全部设备
            if (selectLevel == 1) {
//                List<MatchingDeviceLibrary> resultList = matchingDeviceLibraryDao.findAll();
                List<MatchingDeviceLibrary> resultList = matchingDeviceLibraryDao.findAll(getPredicate(matchingDeviceSelectVo).build());
                return resultList;
            } else {
                throw new ApiException(ResultUtil.failed("单位等级只能为1,2,3"));
            }
        }
    }

    /**
     * @return 所有类型
     */
    @Override
    public List<String> getAllModel() {
        Set<String> models = new HashSet<>();
        matchingDeviceLibraryDao.findAll().forEach(matchingDeviceLibrary -> models.add(matchingDeviceLibrary.getModel()));
        return new ArrayList<>(models);
    }

    /**
     * @return 所有名称
     */
    @Override
    public List<String> getAllName() {
        Set<String> names = new HashSet<>();
        matchingDeviceLibraryDao.findAll().forEach(matchingDeviceLibrary -> names.add(matchingDeviceLibrary.getName()));
        return new ArrayList<>(names);
    }

    @Override
    public List<String> findByModelForSeqNumber(String model) {
        //根据型号查询是否是第一次生成    如果不是取出来最大值
        List<MatchingDeviceLibrary> matchingDeviceLibraryList = matchingDeviceLibraryDao.findAllByModel(model);
        return matchingDeviceLibraryList.stream().filter(matchingDeviceLibrary -> matchingDeviceLibrary.getSeqNumber().contains(model))
                .map(matchingDeviceLibrary -> matchingDeviceLibrary.getSeqNumber().substring(matchingDeviceLibrary.getSeqNumber().length()-4))
                .sorted(Comparator.comparing(String::toString).reversed())
                .collect(Collectors.toList());
    }

    @Override
    public void relationDevice(RelationDeviceVo relationDeviceVo) {
        Integer matchingDeviceId = relationDeviceVo.getMatchingDeviceId();
        MatchingDeviceLibrary matchingDeviceLibrary = getOne(matchingDeviceId);
        matchingDeviceLibrary.setDeviceId(relationDeviceVo.getDeviceId());
        update(matchingDeviceLibrary);
    }

    @Override
    public Map<String, MatchingDeviceLibrary> getAllMatchingDeviceSeqNumber() {
        List<MatchingDeviceLibrary> matchingDeviceLibraries = matchingDeviceLibraryDao.findAll();
        return matchingDeviceLibraries.stream().collect(Collectors.toMap(
                MatchingDeviceLibrary::getSeqNumber, Function.identity()));
    }

    @Override
    public void printRfid(List<RfidPrintVo> rfid) {
        Map<String, MatchingDeviceLibrary> map = getAllMatchingDeviceSeqNumber();

        List<DeviceLogDto> deviceLogDtos = new ArrayList<>();
        List<PrintVo> printVos = new ArrayList<>();
        //调用打印服务 批量打印
        for (RfidPrintVo printVo : rfid) {
            MatchingDeviceLibrary matchingDeviceLibrary = map.get(printVo.getMatchingDeviceSeq());
            PrintVo printVo1 = new PrintVo(RfidServiceImpl.completeRfidStr(
                    matchingDeviceLibrary.getSeqNumber()),
                    matchingDeviceLibrary.getModel(),
                    matchingDeviceLibrary.getName(),
                    matchingDeviceLibrary.getSeqNumber());
            printVos.add(printVo1);
            if ("".equals(matchingDeviceLibrary.getRfidCardId())) {
                matchingDeviceLibrary.setRfidCardId(RfidServiceImpl.completeRfidStr(
                        matchingDeviceLibrary.getSeqNumber()));
                update(matchingDeviceLibrary);
                deviceLogDtos.add(new DeviceLogDto(matchingDeviceLibrary.getId(), "打印标签",
                        null,null,null));
            }
            else {
                deviceLogDtos.add(new DeviceLogDto(matchingDeviceLibrary.getId(), "更换标签",
                        null,null,null));
            }
        }
        rfidService.printString(printVos.stream().sorted(Comparator.comparing(PrintVo::getRfidContent))
                .collect(Collectors.toList()));
        deviceLogService.addAllLog(deviceLogDtos);
    }

    @Override
    public MatchingDeviceLibrary printRfid(Integer matchingDeviceId) {
        MatchingDeviceLibrary matchingDeviceLibrary = getOne(matchingDeviceId);
        DeviceLogDto deviceLogDto = null;
//        List<PrintVo> printVos = new ArrayList<>();
        PrintVo printVo1 = new PrintVo(RfidServiceImpl.completeRfidStr(
                matchingDeviceLibrary.getSeqNumber()), matchingDeviceLibrary.getModel(),
                matchingDeviceLibrary.getName(), matchingDeviceLibrary.getSeqNumber());
        if ("".equals(matchingDeviceLibrary.getRfidCardId())) {
            matchingDeviceLibrary.setRfidCardId(RfidServiceImpl.completeRfidStr(matchingDeviceLibrary.getSeqNumber()));
            if (rfidService.printString1(printVo1)){
                update(matchingDeviceLibrary);
                deviceLogDto = new DeviceLogDto(matchingDeviceLibrary.getId(), "打印标签", null, null, null);
            }
        }
        else {
            rfidService.printString1(printVo1);
            deviceLogDto = new DeviceLogDto(matchingDeviceLibrary.getId(), "更新标签", null, null, null);

        }
//        printVos.add(printVo1);
//        rfidService.printString(printVos.stream().sorted(Comparator.comparing(PrintVo::getRfidContent)).collect(Collectors.toList()));
        deviceLogService.addLog(deviceLogDto);
        return matchingDeviceLibrary;
    }

    @Override
    public List<String> getAllMatchingDeviceLibraryListSeqNumberList() {

        return   matchingDeviceLibraryDao.findAll().stream().map(MatchingDeviceLibrary::getSeqNumber)
                .collect(Collectors.toList());
    }


    /**
     * @param matchingDeviceSelectVo 配套设备查询vo
     *                               创建通用查询条件筛选器
     */
    private PredicateBuilder<MatchingDeviceLibrary> getPredicate(MatchingDeviceSelectVo matchingDeviceSelectVo) {
        PredicateBuilder<MatchingDeviceLibrary> predicateBuilder = Specifications.and();
        if (matchingDeviceSelectVo.getType() != null) {
            predicateBuilder.eq("type", matchingDeviceSelectVo.getType());
        }
        if (matchingDeviceSelectVo.getModel() != null) {
            predicateBuilder.eq("model", matchingDeviceSelectVo.getModel());
        }
        if (matchingDeviceSelectVo.getName() != null) {
            predicateBuilder.eq("name", matchingDeviceSelectVo.getName());
        }
        if (matchingDeviceSelectVo.getContent() != null) {
            Class<MatchingDeviceLibrary> taskEntityClass = MatchingDeviceLibrary.class;
            Field[] declaredFields = taskEntityClass.getDeclaredFields();
            PredicateBuilder<MatchingDeviceLibrary> p = Specifications.or();
            for (Field field : declaredFields) {
                if (field.getType().equals(String.class) && field.getAnnotation(Transient.class) == null) {
                    p.like(field.getName(), "%" + matchingDeviceSelectVo.getContent() + "%");
                }
            }
            predicateBuilder.predicate(p.build());
        }
        if (matchingDeviceSelectVo.getModelDim()!=null){
            predicateBuilder.like("model","%" +matchingDeviceSelectVo.getModelDim()+"%");
        }
        if (matchingDeviceSelectVo.getNameDim()!=null){
            predicateBuilder.like("name","%" +matchingDeviceSelectVo.getNameDim()+"%");

        }
        if (matchingDeviceSelectVo.getSeqDim()!=null){
            predicateBuilder.like("seqNumber","%" +matchingDeviceSelectVo.getSeqDim()+"%");

        }
        if (matchingDeviceSelectVo.getTypeDim()!=null){
            predicateBuilder.like("type","%" +matchingDeviceSelectVo.getTypeDim()+"%");
        }

        if (matchingDeviceSelectVo.getIsPrint()!=null){
            if (matchingDeviceSelectVo.getIsPrint()==1){
                predicateBuilder.notIn("rfidCardId", "");
            }
            else if (matchingDeviceSelectVo.getIsPrint()==0){
                predicateBuilder.in("rfidCardId", "");
            }
        }
        return predicateBuilder;
    }
}
