package cn.iocoder.yudao.module.system.service.commonlyused;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.bpm.api.model.BpmModelApi;
import cn.iocoder.yudao.module.bpm.api.model.vo.BpmModelRpcVO;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthPermissionInfoRespVO;
import cn.iocoder.yudao.module.system.controller.admin.commonlyused.vo.CommonlyUsedPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.commonlyused.vo.CommonlyUsedRespVO;
import cn.iocoder.yudao.module.system.controller.admin.commonlyused.vo.CommonlyUsedSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.commonlyused.vo.CommonlyUsedVO;
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.commonlyused.CommonlyUsedDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
import cn.iocoder.yudao.module.system.dal.mysql.commonlyused.CommonlyUsedMapper;
import cn.iocoder.yudao.module.system.service.permission.MenuService;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 用户常用应用配置 Service 实现类
 *
 * @author 艾楷
 */
@Service
@Validated
public class CommonlyUsedServiceImpl implements CommonlyUsedService {

    @Resource
    private CommonlyUsedMapper commonlyUsedMapper;
    @Resource
    private PermissionService permissionService;
    @Resource
    private MenuService menuService;
    @Resource
    private BpmModelApi bpmModelApi;

    @Override
    public Long createCommonlyUsed(CommonlyUsedSaveReqVO createReqVO) {
        // 插入
        CommonlyUsedDO commonlyUsed = BeanUtils.toBean(createReqVO, CommonlyUsedDO.class);
        commonlyUsedMapper.insert(commonlyUsed);
        // 返回
        return commonlyUsed.getId();
    }

    @Override
    public void updateCommonlyUsed(CommonlyUsedSaveReqVO updateReqVO) {
        // 更新
        CommonlyUsedDO updateObj = BeanUtils.toBean(updateReqVO, CommonlyUsedDO.class);
        commonlyUsedMapper.updateById(updateObj);
    }

    @Override
    public void deleteCommonlyUsed(Long id) {
        // 删除
        commonlyUsedMapper.deleteById(id);
    }


    @Override
    public CommonlyUsedDO getCommonlyUsed(Long id) {
        return commonlyUsedMapper.selectById(id);
    }

    @Override
    public PageResult<CommonlyUsedDO> getCommonlyUsedPage(CommonlyUsedPageReqVO pageReqVO) {

        return commonlyUsedMapper.selectPage(pageReqVO);
    }

    @Override
    public CommonlyUsedVO getCommonlyUsedList() {
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        CommonlyUsedVO vo = new CommonlyUsedVO();
        // -- 搜索我的常用
        List<CommonlyUsedDO> list = commonlyUsedMapper.selectList(new LambdaQueryWrapper<CommonlyUsedDO>()
                .eq(CommonlyUsedDO::getDeleted, 0).eq(CommonlyUsedDO::getUserId, userId).orderByAsc(CommonlyUsedDO::getSort));
        Map<String, List<CommonlyUsedDO>> map = list.stream().collect(Collectors.groupingBy(a -> a.getType() + "_" + a.getObjectId()));
        // -- 获取菜单列表
        List<MenuDO> menuList = menuService.getAvailableMenuListByRoleId();
        // -- 获取流程列表
        List<BpmModelRpcVO> modelList = bpmModelApi.getModelList().getCheckedData();
        List<String> menuIds = new ArrayList<>();
        List<String> processIds = new ArrayList<>();
        if (!list.isEmpty()) {
            // 区分出菜单和流程
            List<CommonlyUsedDO> myProcessList = list.stream().filter(a -> a.getType() == 1).collect(Collectors.toList());
            List<CommonlyUsedDO> myMenuList = list.stream().filter(a -> a.getType() == 2).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(myProcessList)) {
                processIds = myProcessList.stream().map(CommonlyUsedDO::getObjectId).collect(Collectors.toList());
            }
            if (CollectionUtil.isNotEmpty(myMenuList)) {
                menuIds = myMenuList.stream().map(CommonlyUsedDO::getObjectId).collect(Collectors.toList());
            }
        }

        List<CommonlyUsedRespVO> commonlyUsedRespVOS = new ArrayList<>();
        Map<Long, MenuDO> menuMap = menuList.stream().collect(Collectors.toMap(MenuDO::getId, a -> a));
        for (MenuDO menuDO : menuList) {
            menuDO.setSelectedFlag(false);
            if (menuIds.contains(String.valueOf(menuDO.getId()))) {
                menuDO.setSelectedFlag(true);
                // -- 是菜单的才返回回去
                if (menuDO.getType() == 2) {
                    List<CommonlyUsedDO> menus = map.get("2" + "_" + menuDO.getId());
                    CommonlyUsedDO commonlyUsedDO = menus.get(0);
                    CommonlyUsedRespVO commonlyUsedRespVO = BeanUtil.copyProperties(commonlyUsedDO, CommonlyUsedRespVO.class);
                    commonlyUsedRespVO.setImg(menuDO.getImg());
                    commonlyUsedRespVO.setName(menuDO.getName());
                    // -- 这里的路由需要拼接
                    List<String> routingList = new ArrayList<>();
                    routingList.add(menuDO.getPath());
                    this.recursiveConcatenationOfRoutingAddresses(routingList, menuDO, menuMap);
                    //list反转
                    String routing = String.join("/", Lists.reverse(routingList));
                    commonlyUsedRespVO.setRouting(routing);
                    commonlyUsedRespVOS.add(commonlyUsedRespVO);
                }
            }
        }

        for (BpmModelRpcVO modelRpcVO : modelList) {
            modelRpcVO.setSelectedFlag(false);
            if (processIds.contains(String.valueOf(modelRpcVO.getId()))) {
                modelRpcVO.setSelectedFlag(true);
                List<CommonlyUsedDO> models = map.get("1" + "_" + modelRpcVO.getId());
                CommonlyUsedDO commonlyUsedDO = models.get(0);
                CommonlyUsedRespVO commonlyUsedRespVO = BeanUtils.toBean(commonlyUsedDO, CommonlyUsedRespVO.class);
                commonlyUsedRespVO.setImg(modelRpcVO.getProcessImg());
                commonlyUsedRespVO.setName(modelRpcVO.getName());
                commonlyUsedRespVO.setRouting(modelRpcVO.getFormCustomCreatePath());
                commonlyUsedRespVOS.add(commonlyUsedRespVO);
            }
        }

        List<AuthPermissionInfoRespVO.MenuVO> menus = AuthConvert.INSTANCE.buildMenuTree(menuList);
        vo.setMenus(menus);
        vo.setCommonlyUsedRespVOS(commonlyUsedRespVOS);
        vo.setModelList(modelList);
        return vo;
    }

    /**
     * 递归拼接路由
     *
     * @param routingList
     * @param menuDO
     * @param menuMap
     */
    private void recursiveConcatenationOfRoutingAddresses(List<String> routingList, MenuDO menuDO, Map<Long, MenuDO> menuMap) {
        if (menuDO.getParentId() == 0L) {
            return;
        }
        //获取上级
        MenuDO parentMenuDO = menuMap.get(menuDO.getParentId());
        routingList.add(parentMenuDO.getPath());
        this.recursiveConcatenationOfRoutingAddresses(routingList, parentMenuDO, menuMap);
    }


    @Override
    public void batchUpdate(List<CommonlyUsedSaveReqVO> list) {
        List<CommonlyUsedDO> updateList = BeanUtils.toBean(list, CommonlyUsedDO.class);
        commonlyUsedMapper.updateBatch(updateList);
    }

    @Override
    public void batchDelete(List<Long> ids) {
        commonlyUsedMapper.deleteBatchIds(ids);
    }

    @Override
    public void batchCreateOrEditOrDel(List<CommonlyUsedSaveReqVO> list) {
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        if (CollectionUtil.isEmpty(list)) {
            commonlyUsedMapper.delete(new LambdaQueryWrapper<CommonlyUsedDO>().eq(CommonlyUsedDO::getUserId, userId));
            return;
        }
        List<CommonlyUsedDO> oldList = commonlyUsedMapper.selectList(new LambdaQueryWrapper<CommonlyUsedDO>().eq(CommonlyUsedDO::getUserId, userId));
        List<CommonlyUsedDO> newList = BeanUtils.toBean(list, CommonlyUsedDO.class);

        if (CollectionUtil.isEmpty(oldList)) {
            for (CommonlyUsedDO commonlyUsedDO : newList) {
                commonlyUsedDO.setUserId(userId);
            }
            commonlyUsedMapper.insertBatch(newList);
            return;
        }
        //根据类型和objectId 分组
        Map<String, CommonlyUsedDO> oldMap = oldList.stream().collect(Collectors.toMap(a -> a.getType() + "_" + a.getObjectId(), a -> a));
        Map<String, CommonlyUsedDO> newMap = newList.stream().collect(Collectors.toMap(a -> a.getType() + "_" + a.getObjectId(), a -> a));
        // -- 需要删除的
        List<String> delIds = new ArrayList<>(CollectionUtil.subtract(oldMap.keySet(), newMap.keySet()));
        if (CollectionUtil.isNotEmpty(delIds)) {
            List<Long> delIdList = new ArrayList<>();
            for (String delId : delIds) {
                delIdList.add(oldMap.get(delId).getId());
            }
            commonlyUsedMapper.deleteBatchIds(delIdList);
        }
        // -- 需要保存的
        List<String> saveIds = new ArrayList<>(CollectionUtil.subtract(newMap.keySet(), oldMap.keySet()));
        if (CollectionUtil.isNotEmpty(saveIds)) {
            List<CommonlyUsedDO> saveIdList = new ArrayList<>();
            for (String saveId : saveIds) {
                CommonlyUsedDO commonlyUsedDO = newMap.get(saveId);
                commonlyUsedDO.setUserId(userId);
                saveIdList.add(newMap.get(saveId));
            }
            commonlyUsedMapper.insertBatch(saveIdList);
        }
        // -- 需要编辑的
        List<String> editIds = new ArrayList<>(CollectionUtil.intersectionDistinct(newMap.keySet(), oldMap.keySet()));
        if (CollectionUtil.isNotEmpty(editIds)) {
            List<CommonlyUsedDO> editList = new ArrayList<>();
            for (String editId : editIds) {
                editList.add(newMap.get(editId));
            }
            commonlyUsedMapper.updateBatch(editList);
        }
    }
}
