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.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.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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.persistence.Transient;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.CompletableFuture;
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;

    @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);
            //如果是市或县，筛选出创建单位在units中的设备
            if (selectLevel == 3 || selectLevel == 2) {
                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();
                return PageUtil.getPerPage(matchingDeviceSelectVo.getPage(), matchingDeviceSelectVo.getSize(), resultList, pageable);
            } 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);
    }

    /**
     * @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()+"%");
        }
        return predicateBuilder;
    }
}
