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

import com.tykj.dev.device.user.base.ret.*;
import com.tykj.dev.device.user.cache.UnitsCache;
import com.tykj.dev.device.user.subject.dao.AreaDao;
import com.tykj.dev.device.user.subject.dao.UnitsDao;
import com.tykj.dev.device.user.subject.entity.Area;
import com.tykj.dev.device.user.subject.entity.SecurityUser;
import com.tykj.dev.device.user.subject.entity.Units;
import com.tykj.dev.device.user.subject.service.UnitsService;
import com.tykj.dev.misc.exception.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zjm
 * @version 1.0.0
 * @ClassName UnitsServiceImpl.java
 * @Description TODO
 * @createTime 2020年07月28日 10:14:00
 */
@Service
@Slf4j
public class UnitsServiceImpl implements UnitsService {
    @Autowired
    UnitsDao unitsDao;
    @Autowired
    AreaDao areaDao;
    @Autowired
    UnitsCache unitsCache;
    @Override
    public Units findById(Integer unitId) {
        Optional<Units> unit = unitsDao.findById(unitId);
        return unit.orElse(null);
    }

    @Override
    public Units findbyName(String name) {
        return unitsDao.findByName(name);
    }

    @Override
    public Units findUnitAreaId(Integer areaId) {
        return unitsDao.findByAreaId(areaId).get(0);
    }

    @Override
    public List<Units> findListById(Integer leven) {
        return unitsDao.findAllByLevel(leven);
    }

    @Override
    public List<AreaVo> findListAreaUnitsVo(SecurityUser securityUser) {
        return new ArrayList<>();
    }

    /**
     * 根据所在区域是省还是市
     * 省 则把下属市以及市下属都区都单位统一放入市AreaVo 在放入List<AreaVo> 集合中。
     * 市 则把下属区都单位放入市都AreaVo对象中
     * @param thisArea 本单位区域
     * @param areas 下级区域列表
     */
    private List<LeftNavigation> provinceAndCity(Area thisArea,List<Area> areas,List<LeftNavigation> leftNavigationList){
        if (thisArea.getType()==1) {
            areas.forEach(area -> {
                LeftNavigation leftNavigation = area.toLeftNavigation();
                List<LeftNavigation> leftNavigationList1 = unitsDao.findAllByAreaId(area.getId()).stream().map(Units::toLeftNavigation).collect(Collectors.toList());
                List<Area> countys = areaDao.findAllByFatherId(area.getId());
                if (countys != null && countys.size() != 0) {
                    countys.forEach(
                            area1 -> {
                                leftNavigationList1.addAll(unitsDao.findAllByAreaId(area1.getId()).stream().map(Units::toLeftNavigation).collect(Collectors.toList()));
                            }
                    );
                }
                leftNavigation.setLeftNavigations(leftNavigationList1.stream().sorted(Comparator.comparing(LeftNavigation::getOrder,Comparator.nullsLast(Integer::compareTo))).collect(Collectors.toList()));
                leftNavigationList.add(leftNavigation);
            });
        }else if (thisArea.getType()==2){
            areas.forEach(area -> leftNavigationList.addAll(unitsDao.findAllByAreaId(area.getId()).stream().map(Units::toLeftNavigation).sorted(Comparator.comparing(LeftNavigation::getOrder,Comparator.nullsLast(Integer::compareTo))).collect(Collectors.toList())));
        }else {
            return leftNavigationList;
        }
        return leftNavigationList;
    }


    @Override
    public List<Units> findListlevenGreaterThanEqual(Integer leven) {
        return unitsDao.findAllByLevelGreaterThanEqual(leven);
    }


    @Override
    public List<Integer> findListSubordinateId(Integer unitsId) {
      Integer areaId = unitsDao.findById(unitsId).get().getAreaId();
      List<Integer> areaIds=areaDao.findAllByFatherId(areaId).stream().map(Area::getId).collect(Collectors.toList());
        return unitsDao.findAllByAreaIdIn(areaIds).stream().map(Units::getUnitId).collect(Collectors.toList());
    }

    @Override
    public List<UnitsVo> findListVoSubordinateAreaId(Integer areaId) {
        List<UnitsVo> unitsVos=new ArrayList<>();
        List<Integer> areaIds=areaDao.findAllByFatherId(areaId).stream().map(Area::getId).collect(Collectors.toList());
        if (areaIds.size() != 0) {
            unitsVos= unitsDao.findAllByAreaIdIn(areaIds).stream().map(Units::toVo).collect(Collectors.toList());
        }
        return unitsVos;
    }

    @Override
    public List<UnitsVo> findListVoAreaId(Integer areaId) {
        return unitsDao.findAllByAreaId(areaId).stream().map(Units::toVo).collect(Collectors.toList());
    }

    @Override
    public List<UnitsTrainVo> findListUnitsTrainVo(Integer unitsId) {
        Integer areaId = unitsDao.findById(unitsId).get().getAreaId();
        List<Integer> areaIds=areaDao.findAllByFatherId(areaId).stream().map(Area::getId).collect(Collectors.toList());
        return unitsDao.findAllByAreaIdIn(areaIds).stream().map(Units::toUnitsTrainVo).collect(Collectors.toList());
    }

    @Override
    public List<Integer> findSuperiorByunitsId(Integer unitsId) {
        Area area= areaDao.findById(this.findById(unitsId).getAreaId()).get();
        return unitsDao.findAllByAreaId(area.getFatherId()).stream().map(Units::getUnitId).collect(Collectors.toList());
    }

    @Override
    public Units findByAreaId(Integer unitsId) {

        return  unitsDao.findAllByAreaId(
                areaDao.findById(
                        findById(unitsId).getAreaId()
                ).get().getFatherId()
        ).get(0);

    }

    @Override
    public List<Units> findBySubordinate(Integer unitsId) {
       Units units =  unitsDao.findById(unitsId).get();
       List<Integer> areaIds= areaDao.findAllByFatherId(units.getAreaId()).stream().map(Area::getId).collect(Collectors.toList());
       List<Units> units1=  unitsDao.findAllByAreaIdIn(areaIds);
       if (units.getLevel()==1){
           units1.add(units);
           units1.addAll(unitsDao.findAllByType(2));
       }
       return units1.stream().sorted(Comparator.comparing(Units::getShowOrder)).collect(Collectors.toList());
    }

    @Override
    public List<Units> findBySubordinateNotOneself(Integer unitsId) {
        Units units =  unitsDao.findById(unitsId).get();
        List<Integer> areaIds= areaDao.findAllByFatherId(units.getAreaId()).stream().map(Area::getId).collect(Collectors.toList());
        List<Units> units1=  unitsDao.findAllByAreaIdIn(areaIds);
        if (units.getLevel()==1){
//            units1.add(units);
            units1.addAll(unitsDao.findAllByType(2));
        }
        return units1.stream().sorted(Comparator.comparing(Units::getShowOrder)).collect(Collectors.toList());
    }

    @Override
    public List<String> findBySubordinateUnitName(Integer unitsId) {
        Units units =  unitsDao.findById(unitsId).get();
        List<Integer> areaIds= areaDao.findAllByFatherId(units.getAreaId()).stream().map(Area::getId).collect(Collectors.toList());
        List<String> list=new ArrayList<>();
        list.add(units.getName());
        unitsDao.findAllByAreaIdIn(areaIds).forEach(
                units1 -> list.add(units1.getName())
        );
        return list;
    }

    @Override
    public UnitsPage selectPage(Integer page, Integer size) {
        Pageable pageable = PageRequest.of(page, size, Sort.Direction.ASC, "level");
        Page<Units> unitsPage = unitsDao.findAll(pageable);
        List<Units> list=unitsPage.getContent();
        list.forEach(units -> {
            if (units.getAreaId()>0) {
                units.setAreaName(areaDao.findById(units.getAreaId()).get().getName());
            }
            else if (units.getType()==2){
                units.setAreaName("浙江省");
            }
            else {
                units.setAreaName("-");
            }
        });
        return UnitsPage.builder().data(list)
                .page(page)
                .size(size)
                .total(Math.toIntExact(unitsPage.getTotalElements()))
                .build();
    }

    @Override
    public List<Units> findByUserIdUnitsTrainListVo(Integer unitsId) {
        Optional<Units> unitsOptional = unitsDao.findById(unitsId);
        if (unitsOptional.isPresent()) {
            Units units=unitsOptional.get();
            List<Integer> areaIds = areaDao.findAllByFatherId(units.getAreaId()).stream().map(Area::getId).collect(Collectors.toList());
            return unitsDao.findAllByAreaIdIn(areaIds);
        }else {
            throw new ApiException(ResponseEntity.status(500).body("单位没有查到"));
        }
    }

    @Override
    public List<Units> findAllByIdIn(List<Integer> ids) {
        return unitsDao.findAllById(ids);
    }

    @Override
    public List<Units> finAllDirectlUnderUnits() {
        return unitsDao.findAllByType(2);
    }

    @Override
    public LeftNavigation findLeftNavigation(SecurityUser securityUser) {
        LeftNavigation leftNavigation=new LeftNavigation();
        List<LeftNavigation> leftNavigationList=new ArrayList<>();
        Integer areaId=securityUser.getCurrentUserInfo().getUnits().getAreaId();
        Area belongsArea= areaDao.findById(areaId).get();
        if (belongsArea.getType()==1|| belongsArea.getType()==2){
            leftNavigation = belongsArea.toLeftNavigation();
            leftNavigationList=  unitsDao.findAllByAreaId(belongsArea.getId()).stream().map(Units::toLeftNavigation).collect(Collectors.toList());
        }
        if (belongsArea.getType()==1){
            //把省直属组合一下 直属单位（type=2） 处室单位（type=4）
            leftNavigationList.addAll(unitsDao.findAllByType(4).stream().map(Units::toLeftNavigation).collect(Collectors.toList()));
            List<LeftNavigation> leftNavigationList2=unitsDao.findAllByType(2).stream().map(Units::toLeftNavigation).collect(Collectors.toList());
            LeftNavigation leftNavigation2=new LeftNavigation(0,"省直属",leftNavigationList2, UUID.randomUUID().toString(),1,22);
            leftNavigationList.add(leftNavigation2);
        }
        List<Area> areas= areaDao.findAllByFatherId(areaId);
        if (areas.size()!=0) {
            provinceAndCity(belongsArea,areas,leftNavigationList);
        }else {
            leftNavigation= belongsArea.toLeftNavigation();
            leftNavigationList= unitsDao.findAllByAreaId(belongsArea.getId()).stream().map(Units::toLeftNavigation).collect(Collectors.toList());
        }

        leftNavigation.setLeftNavigations(leftNavigationList.stream().sorted(Comparator.comparing(LeftNavigation::getOrder,Comparator.nullsLast(Integer::compareTo))).collect(Collectors.toList()));

        return leftNavigation;
    }

    @Override
    public List<Units> findSuperiorUnitsList() {

        return unitsDao.findAllByType(3);
    }

    @Override
    public List<Units> findDirectlyUnder() {
        List<Units> unitsList= unitsDao.findAllByType(2);
        unitsList.addAll(unitsDao.findAllByType(4));
        return unitsList;
    }


    @Override
    public List<Units> findSubordinateList(Integer unitsId) {
        Units units =  unitsDao.findById(unitsId).get();
        List<Integer> areaIds= areaDao.findAllByFatherId(units.getAreaId()).stream().map(Area::getId).collect(Collectors.toList());
        return unitsDao.findAllByAreaIdIn(areaIds);
    }


    @Override
    public Units save(Units units) {
        if (units.getAreaId()!=null&&units.getAreaId()!=0) {
            Optional<Area> optionalArea = areaDao.findById(units.getAreaId());
            if (optionalArea.isPresent()) {
                units.setLevel(optionalArea.get().getType());
            } else {
                throw new ApiException(ResponseEntity.ok("[单位] 没找到对应的区域，请检查"));
            }
        }
        else {
            units.setLevel(4);
        }
        Units units1 = unitsDao.save(units);
        unitsCache.refresh(unitsDao.findAll());
        return units1;
    }

    @Override
    public boolean delete(Integer id) {
        unitsDao.deleteById(id);
        unitsCache.refresh(unitsDao.findAll());
        return true;
    }

    @Override
    public List<Units> findAll() {
        return unitsDao.findAll();
    }

    @Override
    public Units update(Units units) {
        Units units1 = unitsDao.save(units);
        unitsCache.refresh(unitsDao.findAll());
        return units1;
    }
}
