package com.njcn.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.enums.SystemResponseEnum;
import com.njcn.system.pojo.po.DictData;
import com.njcn.user.enums.UserResponseEnum;
import com.njcn.user.mapper.ComponentMapper;
import com.njcn.user.pojo.constant.ComponentState;
import com.njcn.user.pojo.constant.FunctionState;
import com.njcn.user.pojo.dto.ComponentDTO;
import com.njcn.user.pojo.param.ComponentParam;
import com.njcn.user.pojo.po.Component;
import com.njcn.user.pojo.po.Role;
import com.njcn.user.pojo.vo.ComponentVO;
import com.njcn.user.service.IComponentService;
import com.njcn.user.service.IRoleComponentService;
import com.njcn.user.service.IRoleService;
import com.njcn.user.service.IUserRoleService;
import com.njcn.web.utils.RequestUtil;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

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

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author hongawen
 * @since 2021-12-13
 */
@AllArgsConstructor
@Service
public class ComponentServiceImpl extends ServiceImpl<ComponentMapper, Component> implements IComponentService {

    private final ComponentMapper componentMapper;

    private final IRoleService roleService;

    private final IUserRoleService iUserRoleService;

    private final IRoleComponentService roleComponentService;

    private final DicDataFeignClient dicDataFeignClient;

    @Override
    public boolean addComponent(ComponentParam componentParam) {
        checkComponentParam(componentParam, false);
        Component component = new Component();
        BeanUtil.copyProperties(componentParam, component);
        String functionGroup = componentParam.getFunctionGroup().stream().map(String::valueOf).collect(Collectors.joining(","));
        component.setFunctionGroup(functionGroup);
        component.setState(ComponentState.ENABLE);
        if (Objects.equals(componentParam.getPid(), FunctionState.FATHER_PID)) {
            component.setPids(FunctionState.FATHER_PID);
        } else {
            Component fatherComponent = this.lambdaQuery().eq(Component::getId, componentParam.getPid()).one();
            String pidS = fatherComponent.getPids();
            component.setPids(pidS + "," + componentParam.getPid());
        }
        return this.save(component);
    }

    @Override
    public boolean deleteComponent(String id) {
        return this.lambdaUpdate()
                .set(Component::getState, ComponentState.DELETE)
                .in(Component::getId, id)
                .update();
    }

    @Override
    public boolean updateComponent(ComponentParam.ComponentUpdateParam componentParam) {
        checkComponentParam(componentParam, true);
        Component component = new Component();
        BeanUtil.copyProperties(componentParam, component);
        String functionGroup = componentParam.getFunctionGroup().stream().map(String::valueOf).collect(Collectors.joining(","));
        component.setFunctionGroup(functionGroup);
        return this.updateById(component);
    }

    @Override
    public List<ComponentVO> getComponentTree() {
        List<ComponentVO> list = new ArrayList<>();
        List<ComponentVO> result = new ArrayList<>();
        List<ComponentDTO> componentList = componentMapper.getAllComponent();
        if (!CollectionUtils.isEmpty(componentList)){
            componentList.forEach(item -> {
                ComponentVO componentVO = new ComponentVO();
                BeanUtil.copyProperties(item, componentVO);
                componentVO.setFunctionGroup(Arrays.stream(item.getFunctionGroup().split(",")).map(s -> Integer.valueOf(s.trim())).collect(Collectors.toList()));
                list.add(componentVO);
            });
            Map<String,List<ComponentVO>> map = list.stream().filter(m->!Objects.isNull(m.getSystemType())).collect(Collectors.groupingBy(ComponentVO::getSystemType));
            map.forEach((k,v)->{
                DictData dictData = dicDataFeignClient.getDicDataById(k).getData();
                if (Objects.isNull(dictData)){
                    throw new BusinessException(SystemResponseEnum.SYSTEM_TYPE_EMPTY);
                }
                ComponentVO componentVO = new ComponentVO();
                componentVO.setId(dictData.getId());
                componentVO.setName(dictData.getName());
                componentVO.setChildren(
                        v.stream()
                            .filter(fun -> Objects.equals(ComponentState.FATHER_PID, fun.getPid()))
                            .peek(funS -> funS.setChildren(getChildCategoryList(funS, v)))
                            .collect(Collectors.toList()));
                result.add(componentVO);
            });
        }
        return result;
    }

    @Override
    public List<ComponentVO> getUserComponentTree() {
        List<ComponentVO> result = new ArrayList<>();
        List<ComponentVO> componentVOList = new ArrayList<>();
        List<Role> roleList = iUserRoleService.getRoleListByUserId(RequestUtil.getUserIndex());
        if (!CollectionUtils.isEmpty(roleList)) {
            List<ComponentDTO> list;
            if (roleList.stream().anyMatch(item -> "root".equals(item.getCode()))) {
                list = componentMapper.getAllComponent();
            } else {
                List<String> componentList = roleComponentService.selectRoleComponent(roleList.stream().map(Role::getId).collect(Collectors.toList()));
                if (CollectionUtil.isEmpty(componentList)) {
                    return result;
                }
                list = componentMapper.getComponentByList(componentList);
            }
            if (CollectionUtil.isEmpty(list)){
                return result;
            }
            list.forEach(item -> {
                ComponentVO componentVO = new ComponentVO();
                BeanUtil.copyProperties(item, componentVO);
                componentVO.setFunctionGroup(Arrays.stream(item.getFunctionGroup().split(",")).map(s -> Integer.valueOf(s.trim())).collect(Collectors.toList()));
                componentVOList.add(componentVO);
            });
            Map<String,List<ComponentVO>> map = componentVOList.stream().collect(Collectors.groupingBy(ComponentVO::getSystemType));
            map.forEach((k, v)->{
                DictData dictData = dicDataFeignClient.getDicDataById(k).getData();
                if (Objects.isNull(dictData)){
                    throw new BusinessException(SystemResponseEnum.SYSTEM_TYPE_EMPTY);
                }
                ComponentVO componentVO = new ComponentVO();
                componentVO.setName(dictData.getName());
                componentVO.setChildren(
                        v.stream()
                                .filter(fun -> Objects.equals(ComponentState.FATHER_PID, fun.getPid()))
                                .peek(funS -> funS.setChildren(getChildCategoryList(funS, v)))
                                .collect(Collectors.toList()));
                result.add(componentVO);
            });
        }
        return result;
    }

    @Override
    public List<Component> getFatherComponent(String systemType) {
        List<Component> list = new ArrayList<>();
        Component component = new Component();
        component.setId("0");
        component.setName("无");
        list.add(component);
        list.addAll(this.lambdaQuery().eq(Component::getSystemType, systemType).eq(Component::getPid,ComponentState.FATHER_PID).eq(Component::getState, ComponentState.ENABLE).list());
        return list;
    }

    /**
     * 递归组装组件表
     */
    private List<ComponentVO> getChildCategoryList(ComponentVO currMenu, List<ComponentVO> categories) {
        return categories.stream().filter(o -> Objects.equals(o.getPid(), currMenu.getId()))
                .peek(o -> o.setChildren(getChildCategoryList(o, categories)))
                .collect(Collectors.toList());
    }

    /**
     * 校验参数，
     * 1.检查是否存在相同名称的组件
     */
    private void checkComponentParam(ComponentParam componentParam, boolean isExcludeSelf) {
        LambdaQueryWrapper<Component> componentLambdaQueryWrapper = new LambdaQueryWrapper<>();
        componentLambdaQueryWrapper
                .eq(Component::getName, componentParam.getName())
                .eq(Component::getSystemType, componentParam.getSystemType())
                .eq(Component::getState, ComponentState.ENABLE);
        //更新的时候，需排除当前记录
        if (isExcludeSelf) {
            if (componentParam instanceof ComponentParam.ComponentUpdateParam) {
                componentLambdaQueryWrapper.ne(Component::getId, ((ComponentParam.ComponentUpdateParam) componentParam).getId());
            }
        }
        int countByAccount = this.count(componentLambdaQueryWrapper);
        //大于等于1个则表示重复
        if (countByAccount >= 1) {
            throw new BusinessException(UserResponseEnum.COMPONENT_NAME_EXIST);
        }
    }
}
