package com.ningdatech.carapi.sys.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpStatus;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.ningdatech.basic.exception.BaseUncheckedException;
import com.ningdatech.basic.util.ValidatorUtil;
import com.ningdatech.carapi.common.contants.DefValConstants;
import com.ningdatech.carapi.sys.entity.Menu;
import com.ningdatech.carapi.sys.entity.dto.MenuSaveDTO;
import com.ningdatech.carapi.sys.entity.dto.MenuUpdateDTO;
import com.ningdatech.carapi.sys.entity.enumeration.MenuTypeEnum;
import com.ningdatech.carapi.sys.mapper.MenuMapper;
import com.ningdatech.carapi.sys.service.MenuService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.ningdatech.basic.util.StrPool.DEF_PARENT_ID;


/**
 * <p>
 * 业务实现类
 * 菜单
 * </p>
 *
 * @author PoffyZhang
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeByIdWithCache(List<Long> ids) {
        if (ids.isEmpty()) {
            return true;
        }

        List<Long> lastIds = Lists.newArrayList();
        lastIds.addAll(ids);

        //子菜单id
        subMenus(ids,lastIds);

        boolean result = this.removeByIds(lastIds);
        return result;
    }

    private void subMenus(List<Long> ids, List<Long> lastIds) {
        if(CollUtil.isEmpty(ids)){
            return;
        }

        ids.forEach(id -> {
            List<Menu> subMenus = list(Wrappers.lambdaQuery(Menu.class).eq(Menu::getPid, id));
            if(CollUtil.isNotEmpty(subMenus)){
                //添加子菜单ID
                List<Long> subIds = subMenus.stream().map(Menu::getId).collect(Collectors.toList());
                lastIds.addAll(subIds);
                //递归
                subMenus(subIds,lastIds);
            }
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(MenuUpdateDTO data, Long userId) {
        if (MenuTypeEnum.MENU.getCode().equals(data.getType())) {
            if(StrUtil.isBlank(data.getPath())){
                throw new BaseUncheckedException(HttpStatus.HTTP_OK, "【地址栏路径】不能为空");
            }
            if(StrUtil.isBlank(data.getComponent())){
                throw new BaseUncheckedException(HttpStatus.HTTP_OK, "【页面路径】不能为空");
            }
            if (!ValidatorUtil.isUrl(data.getPath())) {
                if(checkPath(data.getId(), data.getPath())){
                    throw new BaseUncheckedException(HttpStatus.HTTP_OK,"【地址栏路径】:{}重复", data.getPath());
                }
            }
        }
        Menu old = getById(data);
        if(Objects.isNull(old)){
            throw new BaseUncheckedException(HttpStatus.HTTP_OK,"您修改的菜单已不存在");
        }
        Menu menu = BeanUtil.toBean(data, Menu.class);
        menu.setUpdateBy(userId);
        return this.updateById(menu);
    }

    public Boolean checkPath(Long id, String path) {
        return baseMapper.selectCount(Wrappers.lambdaQuery(Menu.class).ne(Menu::getId, id).eq(Menu::getPath, path)) > 0;
    }

    public Boolean checkTitle(Long id, String title) {
        return baseMapper.selectCount(Wrappers.lambdaQuery(Menu.class).ne(Menu::getId, id)
                .in(Menu::getType, MenuTypeEnum.MENU.getCode()).eq(Menu::getTitle, title)) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(MenuSaveDTO data, Long userId) {
        if (MenuTypeEnum.MENU.getCode().equals(data.getType())) {
            if(StrUtil.isBlank(data.getPath())){
                throw new BaseUncheckedException(HttpStatus.HTTP_OK, "【地址栏路径】不能为空");
            }
            if(StrUtil.isBlank(data.getComponent())){
                throw new BaseUncheckedException(HttpStatus.HTTP_OK, "【页面路径】不能为空");
            }
            if (!ValidatorUtil.isUrl(data.getPath())) {
                if(checkPath(null, data.getPath())){
                    throw new BaseUncheckedException(HttpStatus.HTTP_OK,"【地址栏路径】:{}重复", data.getPath());
                }
            }
        }
        data.setPid(Convert.toLong(data.getPid(), DEF_PARENT_ID));

        Menu menu = BeanUtil.toBean(data, Menu.class);
        menu.setCreateBy(userId);
        menu.setUpdateBy(userId);
        save(menu);
        return Boolean.TRUE;
    }

    private void checkGeneral(Menu data, boolean isUpdate) {
//        if (data.getIsGeneral() == null) {
//            return;
//        }
//
//        if (data.getIsGeneral()) {
//            // isGeneral 子节点 改成是，父节点全是
//            if (!TreeUtil.isRoot(data.getParentId())) {
//                Menu parent = getById(data.getParentId());
//                Assert.notNull(parent, "父节点不存在");
//                Assert.isTrue(parent.getIsGeneral(), "请先将父节点{} “公共资源”字段修改为：“是”，在修改本节点", parent.getLabel());
//            }
//            return;
//        }

//        if (isUpdate) {
//            // isGeneral 父节点 改成否，子节点全否
//            List<Menu> childrenList = findChildrenByParentId(data.getId());
//            if (CollUtil.isNotEmpty(childrenList)) {
//                childrenList.forEach(item -> {
//                    Assert.isFalse(item.getIsGeneral(), String.format("请先将子节点%s “公共资源”字段修改为：“否”，在修改本节点", item.getLabel()));
//                });
//            }
//        }
    }

    public List<Menu> findChildrenByParentId(Long pid) {
        if(Objects.isNull(pid)){
            throw new BaseUncheckedException(HttpStatus.HTTP_OK, "pid 不能为空");
        }
        return list(Wrappers.lambdaQuery(Menu.class).in(Menu::getPid, pid).orderByAsc(Menu::getSort));
    }

    private void fill(Menu resource) {
        if (resource.getPid() == null || resource.getPid() <= 0) {
            resource.setPid(DefValConstants.PARENT_ID);
        } else {
            Menu parent = getById(resource.getPid());
            if(Objects.isNull(parent)){
                throw new BaseUncheckedException(HttpStatus.HTTP_OK, "请正确填写父级");
            }
        }
    }

}
