/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package me.zhengjie.modules.dm.foodCate.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.dm.foodCate.domain.DmFoodCate;
import me.zhengjie.modules.dm.foodCate.repository.DmFoodCateRepository;
import me.zhengjie.modules.dm.foodCate.service.DmFoodCateService;
import me.zhengjie.modules.dm.foodCate.service.dto.DmFoodCateDto;
import me.zhengjie.modules.dm.foodCate.service.dto.DmFoodCateQueryCriteria;
import me.zhengjie.modules.dm.foodCate.service.mapstruct.DmFoodCateMapper;
import me.zhengjie.modules.system.domain.Menu;
import me.zhengjie.modules.system.domain.Role;
import me.zhengjie.modules.system.domain.User;
import me.zhengjie.modules.system.service.dto.MenuDto;
import me.zhengjie.utils.*;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
* @website https://el-admin.vip
* @description 服务实现
* @author sunmz
* @date 2021-09-15
**/
@Service
@RequiredArgsConstructor
public class DmFoodCateServiceImpl implements DmFoodCateService {

    private final DmFoodCateRepository dmFoodCateRepository;
    private final DmFoodCateMapper dmFoodCateMapper;

    @Override
    public Map<String,Object> queryAll(DmFoodCateQueryCriteria criteria, Pageable pageable){
        Page<DmFoodCate> page = dmFoodCateRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        return PageUtil.toPage(page.map(dmFoodCateMapper::toDto));
    }

    @Override
    public Map<String,Object> queryAll(DmFoodCateQueryCriteria criteria, Boolean isQuery, Pageable pageable) throws Exception {
//        Sort sort = new Sort(Sort.Direction.ASC, "dmFoodCateSort");
        if(isQuery){
            criteria.setPidIsNull(true);
            List<Field> fields = QueryHelp.getAllFields(criteria.getClass(), new ArrayList<>());
            for (Field field : fields) {
                //设置对象的访问权限，保证对private的属性的访问
                field.setAccessible(true);
                Object val = field.get(criteria);
                if("pidIsNull".equals(field.getName())){
                    continue;
                }
                if (ObjectUtil.isNotNull(val)) {
                    criteria.setPidIsNull(null);
                    break;
                }
            }
        }
        Page<DmFoodCate> page = dmFoodCateRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        return PageUtil.toPage(page.map(dmFoodCateMapper::toDto));
    }

    @Override
    public List<DmFoodCateDto> queryAll(DmFoodCateQueryCriteria criteria){
        return dmFoodCateMapper.toDto(dmFoodCateRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
    @Transactional
    public DmFoodCateDto findById(Integer id) {
//        DmFoodCate dmFood = dmFoodCateRepository.findById(id).orElseGet(DmFoodCate::new);
        DmFoodCate dmFood = dmFoodCateRepository.findByCateId(id);
        ValidationUtil.isNull(dmFood.getCateId(),"DmFoodCate","cateId",id);
        return dmFoodCateMapper.toDto(dmFood);
    }

    @Override
    public List<DmFoodCateDto> getSuperior(DmFoodCateDto dto, List<DmFoodCate> objects) {
        if(dto.getPid() == null){
            objects.addAll(dmFoodCateRepository.findByPidIsNull());
            return dmFoodCateMapper.toDto(objects);
        }
        objects.addAll(dmFoodCateRepository.findByPid(dto.getPid()));
        return getSuperior(findById(dto.getPid()), objects);
    }

    @Override
    public List<DmFoodCateDto> buildTree(List<DmFoodCateDto> menuDtos) {
        List<DmFoodCateDto> trees = new ArrayList<>();
        Set<Integer> ids = new HashSet<>();
        for (DmFoodCateDto menuDTO : menuDtos) {
            if (menuDTO.getPid() == null) {
                trees.add(menuDTO);
            }
            for (DmFoodCateDto it : menuDtos) {
                if (menuDTO.getCateId().equals(it.getPid())) {
                    if (menuDTO.getChildren() == null) {
                        menuDTO.setChildren(new ArrayList<>());
                    }
                    menuDTO.getChildren().add(it);
                    ids.add(it.getCateId());
                }
            }
        }
        if(trees.size() == 0){
            trees = menuDtos.stream().filter(s -> !ids.contains(s.getCateId())).collect(Collectors.toList());
        }
        return trees;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(DmFoodCate resources) {
        if(resources.getPid().equals(0)){
            resources.setPid(null);
        }
        if (resources.getUrl().getId() == null){
            resources.setUrl(null);
        }
        dmFoodCateRepository.save(resources);
        // 计算子节点数目
        resources.setSubCount(0);
        // 更新父节点菜单数目
        updateSubCnt(resources.getPid());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(DmFoodCate resources) {
        if(resources.getCateId().equals(resources.getPid())) {
            throw new BadRequestException("上级不能为自己");
        }
        DmFoodCate dmFoodCate = dmFoodCateRepository.findById(resources.getId()).orElseGet(DmFoodCate::new);
        ValidationUtil.isNull( dmFoodCate.getId(),"DmFoodCate","id",resources.getId());

        List<DmFoodCate> dmFoodCateList = dmFoodCateRepository.findByPidUpdate(dmFoodCate.getCateId());

        if(resources.getPid().equals(0)){
            resources.setPid(null);
        }
        if (resources.getUrl().getId() == null){
            resources.setUrl(null);
        }
        // 记录的父节点ID
        Integer oldPid = dmFoodCate.getPid();
        Integer newPid = resources.getPid();

        dmFoodCate.copy(resources);
        dmFoodCateRepository.save(resources);
        // 计算父级菜单节点数目
        updateSubCnt(oldPid);
        updateSubCnt(newPid);

        for (DmFoodCate foodCate : dmFoodCateList){
            foodCate.setPid(resources.getCateId());
            dmFoodCateRepository.save(foodCate);
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAll(Set<DmFoodCate> dmFoodCates) {
        for (DmFoodCate foodCate : dmFoodCates) {
            dmFoodCateRepository.deleteById(foodCate.getId());
            updateSubCnt(foodCate.getPid());
        }
    }

    @Override
    public List<DmFoodCateDto> getMenus(Integer pid) {
        List<DmFoodCate> dmFoodCates;
        if (pid.equals(0)){
            pid = null;
        }
        if(pid != null && !pid.equals(0)){
            dmFoodCates = dmFoodCateRepository.findByPid(pid);
        } else {
            dmFoodCates = dmFoodCateRepository.findByPidIsNull();
        }
        return dmFoodCateMapper.toDto(dmFoodCates);
    }

    @Override
    public DmFoodCate findOne(Integer id) {
        DmFoodCate dmFoodCate = dmFoodCateRepository.findById(id).orElseGet(DmFoodCate::new);
        ValidationUtil.isNull(dmFoodCate.getId(),"DmFoodCate","id",id);
        return dmFoodCate;
    }

    @Override
    public Set<DmFoodCate> getChildMenus(List<DmFoodCate> menuList, Set<DmFoodCate> menuSet) {
        for (DmFoodCate menu : menuList) {
            menuSet.add(menu);
            List<DmFoodCate> menus = dmFoodCateRepository.findByPid(menu.getCateId());
            if(menus!=null && menus.size()!=0){
                getChildMenus(menus, menuSet);
            }
        }
        return menuSet;
    }

    @Override
    public void download(List<DmFoodCateDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (DmFoodCateDto dmFood : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("编号", dmFood.getCateId());
            map.put("名称", dmFood.getCateName());
            map.put("上级编号", dmFood.getPid());
            map.put("图片", dmFood.getPicture());
            map.put("创建者", dmFood.getCreateBy());
            map.put("更新者", dmFood.getUpdatedBy());
            map.put("创建日期", dmFood.getCreateTime());
            map.put("更新时间", dmFood.getUpdateTime());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    private void updateSubCnt(Integer cateId){
        if(cateId != null){
            int count = dmFoodCateRepository.countByPid(cateId);
            dmFoodCateRepository.updateSubCntById(count, cateId);
        }
    }

}