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

import com.github.wenhao.jpa.PredicateBuilder;
import com.github.wenhao.jpa.Specifications;
import com.tykj.dev.device.packing.repository.PackingLibraryDao;
import com.tykj.dev.device.packing.service.PackingLibraryService;
import com.tykj.dev.device.packing.subject.domin.PackingLibrary;
import com.tykj.dev.device.packing.subject.vo.PackingLibrarySelectVo;
import com.tykj.dev.misc.exception.ApiException;
import com.tykj.dev.misc.utils.GetTreeUtils;
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.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.Transient;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author dengdiyi
 */
@Service
public class PackingLibraryServiceImpl implements PackingLibraryService {

    @Autowired
    private PackingLibraryDao packingLibraryDao;

    @Override
    public PackingLibrary addEntity(PackingLibrary packingLibraryEntity) {
        return packingLibraryDao.save(packingLibraryEntity);
    }

    @Override
    public Page<PackingLibrary> getPage(PackingLibrarySelectVo packingLibrarySelectVo, Pageable pageable) {
        return packingLibraryDao.findAll(getSelectSpecification5(packingLibrarySelectVo), pageable);
    }

    @Override
    public Page<PackingLibrary> getInvalidPage(PackingLibrarySelectVo packingLibrarySelectVo, Pageable pageable) {
        return packingLibraryDao.findAll(getSelectSpecification2(packingLibrarySelectVo), pageable);
    }

    @Override
    public List<PackingLibrary> getList(PackingLibrarySelectVo packingLibrarySelectVo) {
        List<PackingLibrary> packingLibraryEntities = packingLibraryDao.findAll(getSelectSpecification(packingLibrarySelectVo));
        //返回父子结构
        Map<Integer, PackingLibrary> nodeCollect =
                packingLibraryEntities.stream().collect(Collectors.toMap(PackingLibrary::getId,packingLibraryEntity -> packingLibraryEntity));
        return GetTreeUtils.parseTreeFromDown(
                packingLibraryEntities,
                PackingLibrary::getId,
                packingLibraryEntity -> Optional.ofNullable(nodeCollect.get(packingLibraryEntity.getPartParentId())),
                PackingLibrary::addChildNode
        );
    }

    @Override
    public List<Integer> getTypeList() {
        List<PackingLibrary> list = packingLibraryDao.findAll();
        Set<Integer> s = new HashSet<>();
        for (PackingLibrary d:list) {
            s.add(d.getType());
        }
        return new ArrayList<>(s);
    }

    @Override
    public List<String> getModelList() {
        List<PackingLibrary> list = packingLibraryDao.findAll();
        Set<String> s = new HashSet<>();
        for (PackingLibrary d:list) {
            s.add(d.getModel());
        }
        return new ArrayList<>(s);
    }

    @Override
    public List<PackingLibrary> selectAllPart(Integer id) {
        PredicateBuilder<PackingLibrary> predicateBuilder = Specifications.and();
        predicateBuilder.eq("isPart",1);
        predicateBuilder.eq("partParentId",id);
        return packingLibraryDao.findAll(predicateBuilder.build());
    }

    @Override
    public PackingLibrary update(PackingLibrary packingLibraryEntity) {
        return packingLibraryDao.save(packingLibraryEntity);
    }

    @Override
    public PackingLibrary getOne(Integer id) {
        Optional<PackingLibrary> byId = packingLibraryDao.findById(id);
        if (!byId.isPresent()) {
            throw new ApiException(ResultUtil.failed("id不存在"));
        }
        else {
            return byId.get();
        }
    }

    @Override
    public List<PackingLibrary> getPackingDetail(Integer id) {
        Optional<PackingLibrary> byId = packingLibraryDao.findById(id);
        if (!byId.isPresent()) {
            throw new ApiException(ResultUtil.failed("id不存在"));
        }
        else {
            //添加主件
            List<PackingLibrary> libraryEntities = new ArrayList<>();
            libraryEntities.add(byId.get());
            //添加配件信息
            List<PackingLibrary> p = packingLibraryDao.findAll(getSelectSpecification3(id));
            libraryEntities.addAll(p);
            return libraryEntities;
        }
    }

    @Override
    public List<PackingLibrary> getInvalidDetail(Integer id) {
        Optional<PackingLibrary> byId = packingLibraryDao.findById(id);
        if (!byId.isPresent()) {
            throw new ApiException(ResultUtil.failed("id不存在"));
        }
        else {
            //添加主件
            List<PackingLibrary> libraryEntities = new ArrayList<>();
            libraryEntities.add(byId.get());
            //添加配件信息
            List<PackingLibrary> p = packingLibraryDao.findAll(getSelectSpecification4(id));
            libraryEntities.addAll(p);
            return libraryEntities;
        }
    }

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

    private Specification<PackingLibrary> getSelectSpecification(PackingLibrarySelectVo packingLibrarySelectVo) {
        PredicateBuilder<PackingLibrary> predicateBuilder = Specifications.and();
        if (packingLibrarySelectVo != null) {
            if (packingLibrarySelectVo.getContent() != null) {
                Class<PackingLibrary> packingLibraryEntityClass = PackingLibrary.class;
                Field[] declaredFields = packingLibraryEntityClass.getDeclaredFields();
                PredicateBuilder<PackingLibrary> p = Specifications.or();
                for (Field field : declaredFields) {
                    if (field.getType().equals(String.class)&&field.getAnnotation(Transient.class)==null) {
                        p.like(field.getName(), "%" + packingLibrarySelectVo.getContent() + "%");
                    }
                }
                predicateBuilder.predicate(p.build());
            }
            if (packingLibrarySelectVo.getStartTime() != null) {
                predicateBuilder.gt("createTime", packingLibrarySelectVo.getStartTime());
            }
            if (packingLibrarySelectVo.getEndTime() != null) {
                predicateBuilder.lt("updateTime", packingLibrarySelectVo.getEndTime());
            }
            if (packingLibrarySelectVo.getModel()!=null){
                predicateBuilder.eq("model",packingLibrarySelectVo.getModel());
            }
            if (packingLibrarySelectVo.getType()!=null){
                predicateBuilder.eq("type",packingLibrarySelectVo.getType());
            }
            if(packingLibrarySelectVo.getSecretLevel()!=null){
                predicateBuilder.eq("secretLevel",packingLibrarySelectVo.getSecretLevel());
            }
            if(packingLibrarySelectVo.getInvisibleRange()!=null){
                predicateBuilder.eq("invisibleRange",packingLibrarySelectVo.getInvisibleRange());
            }
            if(packingLibrarySelectVo.getName()!=null){
                predicateBuilder.eq("name",packingLibrarySelectVo.getName());
            }
        }
        predicateBuilder.eq("packingStatus", 2);
        return predicateBuilder.build();
    }

    private Specification<PackingLibrary> getSelectSpecification2(PackingLibrarySelectVo packingLibrarySelectVo) {
        PredicateBuilder<PackingLibrary> predicateBuilder = Specifications.and();
        if (packingLibrarySelectVo != null) {
            if (packingLibrarySelectVo.getContent() != null) {
                Class<PackingLibrary> packingLibraryEntityClass = PackingLibrary.class;
                Field[] declaredFields = packingLibraryEntityClass.getDeclaredFields();
                PredicateBuilder<PackingLibrary> p = Specifications.or();
                for (Field field : declaredFields) {
                    if (field.getType().equals(String.class)&&field.getAnnotation(Transient.class)==null) {
                        p.like(field.getName(), "%" + packingLibrarySelectVo.getContent() + "%");
                    }
                }
                predicateBuilder.predicate(p.build());
            }
            if (packingLibrarySelectVo.getStartTime() != null) {
                predicateBuilder.gt("createTime", packingLibrarySelectVo.getStartTime());
            }
            if (packingLibrarySelectVo.getEndTime() != null) {
                predicateBuilder.lt("updateTime", packingLibrarySelectVo.getEndTime());
            }
            if (packingLibrarySelectVo.getModel()!=null){
                predicateBuilder.eq("model",packingLibrarySelectVo.getModel());
            }
            if (packingLibrarySelectVo.getType()!=null){
                predicateBuilder.eq("type",packingLibrarySelectVo.getType());
            }
            if(packingLibrarySelectVo.getSecretLevel()!=null){
                predicateBuilder.eq("secretLevel",packingLibrarySelectVo.getSecretLevel());
            }
            if(packingLibrarySelectVo.getInvisibleRange()!=null){
                predicateBuilder.eq("invisibleRange",packingLibrarySelectVo.getInvisibleRange());
            }
        }
        predicateBuilder.eq("packingStatus", 3);
        predicateBuilder.eq("isPart",0);
        return predicateBuilder.build();
    }

    private Specification<PackingLibrary> getSelectSpecification3(Integer id) {
        PredicateBuilder<PackingLibrary> predicateBuilder = Specifications.and();
        predicateBuilder.eq("packingStatus", 2);
        predicateBuilder.eq("isPart", 1);
        predicateBuilder.eq("partParentId", id);
        return predicateBuilder.build();
    }

    private Specification<PackingLibrary> getSelectSpecification4(Integer id) {
        PredicateBuilder<PackingLibrary> predicateBuilder = Specifications.and();
        predicateBuilder.eq("packingStatus", 3);
        predicateBuilder.eq("isPart", 1);
        predicateBuilder.eq("partParentId", id);
        return predicateBuilder.build();
    }

    private Specification<PackingLibrary> getSelectSpecification5(PackingLibrarySelectVo packingLibrarySelectVo) {
        PredicateBuilder<PackingLibrary> predicateBuilder = Specifications.and();
        if (packingLibrarySelectVo != null) {
            if (packingLibrarySelectVo.getContent() != null) {
                Class<PackingLibrary> packingLibraryEntityClass = PackingLibrary.class;
                Field[] declaredFields = packingLibraryEntityClass.getDeclaredFields();
                PredicateBuilder<PackingLibrary> p = Specifications.or();
                for (Field field : declaredFields) {
                    if (field.getType().equals(String.class)&&field.getAnnotation(Transient.class)==null) {
                        p.like(field.getName(), "%" + packingLibrarySelectVo.getContent() + "%");
                    }
                }
                predicateBuilder.predicate(p.build());
            }
            if (packingLibrarySelectVo.getStartTime() != null) {
                predicateBuilder.gt("createTime", packingLibrarySelectVo.getStartTime());
            }
            if (packingLibrarySelectVo.getEndTime() != null) {
                predicateBuilder.lt("updateTime", packingLibrarySelectVo.getEndTime());
            }
            if (packingLibrarySelectVo.getModel()!=null){
                predicateBuilder.eq("model",packingLibrarySelectVo.getModel());
            }
            if (packingLibrarySelectVo.getType()!=null){
                predicateBuilder.eq("type",packingLibrarySelectVo.getType());
            }
            if(packingLibrarySelectVo.getSecretLevel()!=null){
                predicateBuilder.eq("secretLevel",packingLibrarySelectVo.getSecretLevel());
            }
            if(packingLibrarySelectVo.getInvisibleRange()!=null){
                predicateBuilder.eq("invisibleRange",packingLibrarySelectVo.getInvisibleRange());
            }
            if(packingLibrarySelectVo.getName()!=null){
                predicateBuilder.eq("name",packingLibrarySelectVo.getName());
            }
        }
        predicateBuilder.eq("packingStatus", 2);
        predicateBuilder.eq("isPart",0);
        return predicateBuilder.build();
    }

}
