package com.yunzhupaas.base.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.ImmutableList;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import com.yunzhupaas.base.entity.*;
import com.yunzhupaas.base.model.online.VisualMenuModel;
import com.yunzhupaas.base.service.*;
import com.yunzhupaas.base.util.visualUtil.PubulishUtil;
import com.yunzhupaas.base.vo.DownloadVO;
import com.yunzhupaas.base.vo.PaginationVO;
import com.yunzhupaas.config.ConfigValueUtil;
import com.yunzhupaas.constant.YunzhupaasConst;
import com.yunzhupaas.constant.MsgCode;
import com.yunzhupaas.base.model.module.MenuSelectVO;
import com.yunzhupaas.database.util.TenantDataSourceUtil;
import com.yunzhupaas.exception.WorkFlowException;
import com.yunzhupaas.model.AppDataInfoModel;
import com.yunzhupaas.model.AppObjectDataModel;
import com.yunzhupaas.model.FlowWorkModel;
import com.yunzhupaas.model.UserMenuModel;
import com.yunzhupaas.model.tenant.*;
import com.yunzhupaas.permission.entity.AuthorizeEntity;
import com.yunzhupaas.permission.entity.PermissionGroupEntity;
import com.yunzhupaas.permission.model.user.UserIdListVo;
import com.yunzhupaas.permission.service.AuthorizeService;
import com.yunzhupaas.permission.service.PermissionGroupService;
import com.yunzhupaas.permission.service.UserService;
import com.yunzhupaas.util.*;
import com.yunzhupaas.exception.DataException;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import com.yunzhupaas.base.ActionResult;
import com.yunzhupaas.base.model.module.*;
import com.yunzhupaas.util.context.SpringContext;
import com.yunzhupaas.emnus.ModuleTypeEnum;
import com.yunzhupaas.util.treeutil.ListToTreeUtil;
import com.yunzhupaas.util.treeutil.SumTree;
import com.yunzhupaas.util.treeutil.TreeViewModel;
import com.yunzhupaas.util.treeutil.newtreeutil.TreeDotUtils;
import com.yunzhupaas.base.vo.ListVO;
import com.yunzhupaas.util.type.AuthorizeType;
import com.yunzhupaas.workflow.service.TemplateApi;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import jakarta.validation.Valid;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 系统功能
 *
 * @author 云筑产品开发平台组
 * @version V3.1.0
 * @copyright 深圳市乐程软件有限公司
 * @date 2023/09/27
 */
@Tag(name = "系统菜单", description = "menu")
@RestController
@RequestMapping("/api/system/Menu")
public class ModuleController extends SuperController<ModuleService, ModuleEntity> {

    @Autowired
    private ModuleService moduleService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private CacheKeyUtil cacheKeyUtil;

    @Autowired
    private SystemService systemService;
    @Autowired
    private PermissionGroupService permissionGroupApi;
    @Autowired
    private ModuleButtonService buttonService;
    @Autowired
    private ModuleColumnService columnService;
    @Autowired
    private ModuleFormService formService;
    @Autowired
    private ModuleDataAuthorizeSchemeService dataAuthorizeSchemeService;
    @Autowired
    private AuthorizeService authorizeApi;
    @Autowired
    private UserService userApi;
    @Autowired
    private ConfigValueUtil configValueUtil;
    @Autowired
    private TemplateApi templateApi;
    @Autowired
    private PubulishUtil pubulishUtil;

    /**
     * 获取菜单列表
     *
     * @param systemId       系统id
     * @param paginationMenu 分页参数
     * @return ignore
     */
    @Operation(summary = "获取菜单列表")
    @Parameters({
            @Parameter(name = "systemId", description = "系统id", required = true)
    })
    @GetMapping("/ModuleBySystem/{systemId}")
    public ActionResult<ListVO<MenuListVO>> list(@PathVariable("systemId") String systemId,
            PaginationMenu paginationMenu) {
        List<ModuleEntity> data = moduleService.getList(systemId, paginationMenu.getCategory(),
                paginationMenu.getKeyword(), paginationMenu.getType(), paginationMenu.getEnabledMark(), null, false);
        // 递归查上级
        Map<String, ModuleEntity> moduleEntityMap = data.stream()
                .collect(Collectors.toMap(ModuleEntity::getId, Function.identity()));
        if (StringUtil.isNotEmpty(paginationMenu.getKeyword())) {
            moduleService.getParentModule(data, moduleEntityMap);
        }
        List<UserMenuModel> list = JsonUtil.getJsonToList(moduleEntityMap.values(), UserMenuModel.class);
        list = list.stream()
                .sorted(Comparator
                        .comparing(UserMenuModel::getSortCode, Comparator.nullsLast(Comparator.naturalOrder()))
                        .thenComparing(UserMenuModel::getCreatorTime, Comparator.nullsLast(Comparator.reverseOrder())))
                .collect(Collectors.toList());
        List<SumTree<UserMenuModel>> menuList = TreeDotUtils.convertListToTreeDot(list);
        List<MenuListVO> menuvo = JsonUtil.getJsonToList(menuList, MenuListVO.class);
        ListVO vo = new ListVO();
        vo.setList(menuvo);
        return ActionResult.success(vo);
    }

    /**
     * 获取菜单列表(下拉框)
     *
     * @param category 分类
     * @param id       主键
     * @return ignore
     */
    @Operation(summary = "获取菜单列表(下拉框)")
    @Parameters({
            @Parameter(name = "category", description = "分类"),
            @Parameter(name = "id", description = "主键", required = true)
    })
    @GetMapping("/Selector/{id}")
    public ActionResult<ListVO<MenuSelectVO>> treeView(String category, @PathVariable("id") String id) {
        String systemId = "App".equals(category) ? UserProvider.getUser().getAppSystemId()
                : UserProvider.getUser().getSystemId();
        List<ModuleEntity> data = moduleService.getList(systemId, category, null, 1, 1, null, false);
        if (!"0".equals(id)) {
            data.remove(moduleService.getInfo(id));
        }
        List<UserMenuModel> list = JsonUtil.getJsonToList(data, UserMenuModel.class);
        List<SumTree<UserMenuModel>> menuList = TreeDotUtils.convertListToTreeDotFilter(list);
        List<MenuSelectVO> menuvo = JsonUtil.getJsonToList(menuList, MenuSelectVO.class);
        ListVO vo = new ListVO();
        vo.setList(menuvo);
        return ActionResult.success(vo);
    }

    /**
     * 获取开发平台菜单
     *
     * @return ignore
     */
    @Operation(summary = "获取开发平台菜单")
    @GetMapping("/SystemSelector")
    public ActionResult<ListVO<MenuSelectVO>> mainSystemSelector() {
        SystemEntity mainSystem = systemService.getInfoByEnCode(YunzhupaasConst.MAIN_SYSTEM_CODE);
        List<ModuleEntity> data = moduleService.getList(mainSystem.getId(), null, null, null, 1, null, false);
        List<UserMenuModel> list = JsonUtil.getJsonToList(data, UserMenuModel.class);
        list.forEach(t -> {
            if ("-1".equals(t.getParentId())) {
                t.setParentId(t.getSystemId());
            }
        });
        UserMenuModel userMenuModel = JsonUtil.getJsonToBean(mainSystem, UserMenuModel.class);
        userMenuModel.setType(0);
        userMenuModel.setParentId("-1");
        list.add(userMenuModel);
        List<SumTree<UserMenuModel>> menuList = TreeDotUtils.convertListToTreeDotFilter(list);
        List<MenuSelectVO> menuvo = JsonUtil.getJsonToList(menuList, MenuSelectVO.class);
        ListVO vo = new ListVO();
        vo.setList(menuvo);
        return ActionResult.success(vo);
    }

    /**
     * 通过系统id获取菜单列表(下拉框)
     *
     * @param category 分类
     * @param id       主键
     * @return ignore
     */
    @Operation(summary = "通过系统id获取菜单列表(下拉框)")
    @Parameters({
            @Parameter(name = "id", description = "主键", required = true),
            @Parameter(name = "systemId", description = "系统主键", required = true),
            @Parameter(name = "enabledMark", description = "查询类型:null-全部，0-禁用，1-启用", required = false)
    })
    @GetMapping("/Selector/{id}/{systemId}")
    public ActionResult<ListVO<MenuSelectAllVO>> treeView(@PathVariable("id") String id,
            @PathVariable("systemId") String systemId,
            @RequestParam("category") String category,
            @RequestParam(value = "enabledMark", required = false) Integer enabledMark) {
        List<ModuleEntity> data = moduleService.getList(systemId, category, null, 1, enabledMark, null, true);
        if (!"0".equals(id)) {
            data.remove(moduleService.getInfo(id));
        }
        List<UserMenuModel> list = JsonUtil.getJsonToList(data, UserMenuModel.class);
        if ("0".equals(systemId)) {
            List<String> moduleAuthorize = new ArrayList<>();
            if (configValueUtil.isMultiTenancy()) {
                TenantAuthorizeModel tenantAuthorizeModel = TenantDataSourceUtil
                        .getCacheModuleAuthorize(UserProvider.getUser().getTenantId());
                moduleAuthorize = tenantAuthorizeModel.getModuleIdList();
            }
            List<SystemEntity> list1 = systemService.getList(null, true, false, true, false, moduleAuthorize);
            list.forEach(t -> {
                if ("-1".equals(t.getParentId())) {
                    t.setParentId(t.getSystemId());
                }
            });
            List<UserMenuModel> jsonToList = JsonUtil.getJsonToList(list1, UserMenuModel.class);
            jsonToList.forEach(t -> {
                t.setType(0);
                t.setParentId("-1");
            });
            list.addAll(jsonToList);
        }
        List<SumTree<UserMenuModel>> menuList = TreeDotUtils.convertListToTreeDotFilter(list);
        List<MenuSelectAllVO> menuvo = JsonUtil.getJsonToList(menuList, MenuSelectAllVO.class);
        ListVO vo = new ListVO();
        vo.setList(menuvo);
        return ActionResult.success(vo);
    }

    /**
     * 通过系统id获取菜单列表(下拉框)
     *
     * @param category 分类
     * @return ignore
     */
    @Operation(summary = "通过系统id获取菜单列表(下拉框)")
    @Parameters({
            @Parameter(name = "id", description = "主键", required = true),
            @Parameter(name = "systemId", description = "系统主键", required = true)
    })
    @GetMapping("/SelectorFilter/{visualId}")
    public ActionResult<ListVO<MenuSelectAllVO>> SelectorFilter(String category,
            @PathVariable("visualId") String visualId) {
        List<ModuleEntity> data = moduleService.getList("0", category, null, 1, 1, null, true);
        List<ModuleEntity> moduleList = moduleService.getModuleList(visualId);
        List<String> moduleIds = new ArrayList<>();
        List<String> systemIds = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(moduleList)) {
            for (ModuleEntity item : moduleList) {
                if ("-1".equals(item.getParentId())) {
                    systemIds.add(item.getSystemId());
                } else {
                    moduleIds.add(item.getParentId());
                }
            }
        }
        List<UserMenuModel> list = JsonUtil.getJsonToList(data, UserMenuModel.class);

        List<String> moduleAuthorize = new ArrayList<>();
        if (configValueUtil.isMultiTenancy()) {
            TenantAuthorizeModel tenantAuthorizeModel = TenantDataSourceUtil
                    .getCacheModuleAuthorize(UserProvider.getUser().getTenantId());
            moduleAuthorize = tenantAuthorizeModel.getModuleIdList();
        }
        List<SystemEntity> list1 = systemService.getList(null, true, false, true, false, moduleAuthorize);
        list.forEach(t -> {
            if ("-1".equals(t.getParentId())) {
                t.setParentId(t.getSystemId());
            }
        });
        List<UserMenuModel> jsonToList = JsonUtil.getJsonToList(list1, UserMenuModel.class);
        jsonToList.forEach(t -> {
            t.setType(0);
            t.setParentId("-1");
        });
        list.addAll(jsonToList);
        for (UserMenuModel userMenuModel : list) {
            if (moduleIds.contains(userMenuModel.getId()) || systemIds.contains(userMenuModel.getId())) {
                userMenuModel.setDisabled(true);
            }
        }
        List<SumTree<UserMenuModel>> menuList = TreeDotUtils.convertListToTreeDotFilter(list);
        List<MenuSelectAllVO> menuvo = JsonUtil.getJsonToList(menuList, MenuSelectAllVO.class);
        ListVO vo = new ListVO();
        vo.setList(menuvo);
        return ActionResult.success(vo);
    }

    /**
     * 获取菜单权限返回权限组
     *
     * @param id 主键
     * @return ignore
     */
    @Operation(summary = "获取菜单权限返回权限组")
    @Parameters({
            @Parameter(name = "id", description = "主键", required = true)
    })
    @GetMapping("/getPermissionGroup/{id}")
    public ActionResult<Map<String, Object>> getPermissionGroup(@PathVariable("id") String id) {
        Map<String, Object> map = new HashMap<>(2);
        int type = 0; // 0未开启权限，1有
        List<FlowWorkModel> list = new ArrayList<>();
        // 获取当前菜单开启了哪些权限
        ModuleEntity entity = moduleService.getInfo(id);
        if (entity == null) {
            return ActionResult.fail(MsgCode.FA001.get());
        }
        // 权限是否被绑定，是否有权限
        List<ModuleButtonEntity> buttonList = buttonService.getListByModuleIds(id);
        List<ModuleColumnEntity> columnList = columnService.getList(id);
        List<ModuleFormEntity> formList = formService.getList(id);
        List<ModuleDataAuthorizeSchemeEntity> dataAuthorizeList = dataAuthorizeSchemeService.getList(id);
        if (buttonList.size() > 0 || columnList.size() > 0 || formList.size() > 0 || dataAuthorizeList.size() > 0) {
            List<AuthorizeEntity> authorizeByItem = authorizeApi.getAuthorizeByItem(AuthorizeType.MODULE,
                    entity.getId());
            List<String> collect = authorizeByItem.stream().map(AuthorizeEntity::getObjectId)
                    .collect(Collectors.toList());
            List<PermissionGroupEntity> permissionGroupByUserId = permissionGroupApi.list(collect);
            list = JsonUtil.getJsonToList(permissionGroupByUserId, FlowWorkModel.class);
            list.forEach(t -> t.setIcon("icon-ym icon-ym-authGroup"));
            if (list.size() > 0) {
                type = 1;
            } else {
                type = 2;
            }
        }
        map.put("list", list);
        map.put("type", type);
        return ActionResult.success(map);
    }

    /**
     * 通过权限组id获取相关权限
     *
     * @param id 主键
     * @return ignore
     */
    @Operation(summary = "通过权限组id获取相关权限")
    @Parameters({
            @Parameter(name = "id", description = "权限组id", required = true)
    })
    @GetMapping("/getPermission/{id}/{permissionId}")
    public ActionResult<ModulePermissionVO> getPermission(@PathVariable("id") String id,
            @PathVariable("permissionId") String permissionId) {
        // 获取当前菜单开启了哪些权限
        ModuleEntity entity = moduleService.getInfo(id);
        if (entity == null) {
            return ActionResult.fail(MsgCode.FA001.get());
        }
        PermissionGroupEntity permissionGroupEntity = permissionGroupApi.info(permissionId);
        if (permissionGroupEntity == null) {
            return ActionResult.fail(MsgCode.FA001.get());
        }
        // 权限组的权限
        List<AuthorizeEntity> authList = authorizeApi.getListByObjectId(Collections.singletonList(permissionId));

        ModulePermissionVO modulePermissionVO = new ModulePermissionVO();

        ModulePermissionModel permissionMemberModel = new ModulePermissionModel();
        permissionMemberModel.setFullName("权限成员");
        permissionMemberModel.setType(1);
        List<ModulePermissionModel.ModulePermissionBaseModel> permissionMember = new ArrayList<>();
        if (StringUtil.isNotEmpty(permissionGroupEntity.getPermissionMember())) {
            List<UserIdListVo> userIdListVos = userApi
                    .selectedByIds(Arrays.asList(permissionGroupEntity.getPermissionMember().split(",")));
            permissionMember = JsonUtil.getJsonToList(userIdListVos,
                    ModulePermissionModel.ModulePermissionBaseModel.class);
        }
        permissionMemberModel.setList(permissionMember);
        modulePermissionVO.setPermissionMember(permissionMemberModel);

        ModulePermissionModel moduleButtonPermissionModel = new ModulePermissionModel();
        moduleButtonPermissionModel.setFullName("按钮权限");
        List<ModuleButtonEntity> buttonList = buttonService.getListByModuleIds(id);
        if (buttonList.size() > 0) {
            int type = 2;
            List<ModuleButtonEntity> collect = buttonList.stream()
                    .filter(t -> authList.stream().map(AuthorizeEntity::getItemId).collect(Collectors.toList())
                            .contains(t.getId()))
                    .collect(Collectors.toList());
            List<ModulePermissionModel.ModulePermissionBaseModel> buttonPermissionList = JsonUtil.getJsonToList(collect,
                    ModulePermissionModel.ModulePermissionBaseModel.class);
            moduleButtonPermissionModel.setList(buttonPermissionList);
            if (buttonPermissionList.size() > 0) {
                type = 1;
            }
            moduleButtonPermissionModel.setType(type);
        }
        modulePermissionVO.setButtonAuthorize(moduleButtonPermissionModel);

        ModulePermissionModel moduleColumnPermissionModel = new ModulePermissionModel();
        moduleColumnPermissionModel.setFullName("列表权限");
        List<ModuleColumnEntity> columnList = columnService.getList(id);
        if (columnList.size() > 0) {
            int type = 2;
            List<ModuleColumnEntity> collect = columnList.stream()
                    .filter(t -> authList.stream().map(AuthorizeEntity::getItemId).collect(Collectors.toList())
                            .contains(t.getId()))
                    .collect(Collectors.toList());
            List<ModulePermissionModel.ModulePermissionBaseModel> buttonPermissionList = JsonUtil.getJsonToList(collect,
                    ModulePermissionModel.ModulePermissionBaseModel.class);
            moduleColumnPermissionModel.setList(buttonPermissionList);
            if (buttonPermissionList.size() > 0) {
                type = 1;
            }
            moduleColumnPermissionModel.setType(type);
        }
        modulePermissionVO.setColumnAuthorize(moduleColumnPermissionModel);

        ModulePermissionModel moduleFromPermissionModel = new ModulePermissionModel();
        moduleFromPermissionModel.setFullName("表单权限");
        List<ModuleFormEntity> formList = formService.getList(id);
        if (formList.size() > 0) {
            int type = 2;
            List<ModuleFormEntity> collect = formList.stream()
                    .filter(t -> authList.stream().map(AuthorizeEntity::getItemId).collect(Collectors.toList())
                            .contains(t.getId()))
                    .collect(Collectors.toList());
            List<ModulePermissionModel.ModulePermissionBaseModel> buttonPermissionList = JsonUtil.getJsonToList(collect,
                    ModulePermissionModel.ModulePermissionBaseModel.class);
            moduleFromPermissionModel.setList(buttonPermissionList);
            if (buttonPermissionList.size() > 0) {
                type = 1;
            }
            moduleFromPermissionModel.setType(type);
        }
        modulePermissionVO.setFormAuthorize(moduleFromPermissionModel);

        ModulePermissionModel moduleDataPermissionModel = new ModulePermissionModel();
        moduleDataPermissionModel.setFullName("数据权限");
        List<ModuleDataAuthorizeSchemeEntity> dataAuthorizeList = dataAuthorizeSchemeService.getList(id);
        if (dataAuthorizeList.size() > 0) {
            int type = 2;
            List<ModuleDataAuthorizeSchemeEntity> collect = dataAuthorizeList.stream()
                    .filter(t -> authList.stream().map(AuthorizeEntity::getItemId).collect(Collectors.toList())
                            .contains(t.getId()))
                    .collect(Collectors.toList());
            List<ModulePermissionModel.ModulePermissionBaseModel> buttonPermissionList = JsonUtil.getJsonToList(collect,
                    ModulePermissionModel.ModulePermissionBaseModel.class);
            moduleDataPermissionModel.setList(buttonPermissionList);
            if (buttonPermissionList.size() > 0) {
                type = 1;
            }
            moduleDataPermissionModel.setType(type);
        }
        modulePermissionVO.setDataAuthorize(moduleDataPermissionModel);

        return ActionResult.success(modulePermissionVO);
    }

    /**
     * 获取菜单列表(下拉框)
     *
     * @param category 分类
     * @return ignore
     */
    @Operation(summary = "获取菜单列表下拉框")
    @GetMapping("/Selector/All")
    public ActionResult<ListVO<MenuSelectAllVO>> menuSelect(String category) {
        List<ModuleEntity> data = moduleService.getList("0", category, null, null, 1, null, false);
        List<UserMenuModel> list = JsonUtil.getJsonToList(data, UserMenuModel.class);
        List<String> moduleAuthorize = new ArrayList<>();
        if (configValueUtil.isMultiTenancy()) {
            TenantAuthorizeModel tenantAuthorizeModel = TenantDataSourceUtil
                    .getCacheModuleAuthorize(UserProvider.getUser().getTenantId());
            moduleAuthorize = tenantAuthorizeModel.getModuleIdList();
        }
        List<SystemEntity> list1 = systemService.getList(null, true, false, false, false, moduleAuthorize);
        list.forEach(t -> {
            t.setHasModule(!"1".equals(String.valueOf(t.getType())));
            if ("-1".equals(t.getParentId())) {
                t.setParentId(t.getSystemId());
            }
        });
        List<UserMenuModel> jsonToList = JsonUtil.getJsonToList(list1, UserMenuModel.class);
        jsonToList.forEach(t -> {
            t.setType(0);
            t.setHasModule(false);
            t.setParentId("-1");
        });
        list.addAll(jsonToList);
        List<SumTree<UserMenuModel>> menuList = TreeDotUtils.convertListToTreeDotFilter(list);
        List<MenuSelectAllVO> menuvo = JsonUtil.getJsonToList(menuList, MenuSelectAllVO.class);
        ListVO vo = new ListVO();
        vo.setList(menuvo);
        return ActionResult.success(vo);
    }

    /**
     * 系统功能类别树形
     *
     * @return ignore
     */
    @Operation(summary = "系统功能类别树形")
    @GetMapping("/{systemId}/TreeView")
    public ActionResult treeView(@PathVariable("systemId") String systemId) {
        List<ModuleEntity> moduleList = moduleService.getList(systemId, null, null, null, null, "0", true);
        List<TreeViewModel> treeList = new ArrayList<>();
        TreeViewModel treeViewModel = new TreeViewModel();
        treeViewModel.setId("apply");
        treeViewModel.setText("软件开发平台");
        treeViewModel.setParentId("0");
        treeViewModel.setImg("fa fa-windows apply");
        treeList.add(treeViewModel);
        for (ModuleEntity entity : moduleList) {
            TreeViewModel treeModel = new TreeViewModel();
            treeModel.setId(entity.getId());
            treeModel.setText(entity.getFullName());
            treeModel.setParentId("apply");
            treeModel.setImg("fa fa-tags");
            treeList.add(treeModel);
        }
        return ActionResult.success(ListToTreeUtil.toTreeView(treeList));
    }

    /**
     * 获取菜单信息
     *
     * @param id 主键值
     * @return ignore
     * @throws DataException ignore
     */
    @Operation(summary = "获取菜单信息")
    @Parameters({
            @Parameter(name = "id", description = "主键值", required = true)
    })
    @SaCheckPermission("system.menu")
    @GetMapping("/{id}")
    public ActionResult<ModuleInfoVO> info(@PathVariable("id") String id) throws DataException {
        ModuleEntity entity = moduleService.getInfo(id);
        ModuleInfoVO vo = JsonUtilEx.getJsonToBeanEx(entity, ModuleInfoVO.class);
        return ActionResult.success(vo);
    }

    /**
     * 新建系统功能
     *
     * @param moduleCrForm 实体对象
     * @return ignore
     */
    @Operation(summary = "新建系统功能")
    @Parameters({
            @Parameter(name = "moduleCrForm", description = "实体对象", required = true)
    })
    @SaCheckPermission("system.menu")
    @PostMapping
    public ActionResult create(@RequestBody @Valid ModuleCrForm moduleCrForm) {
        ModuleEntity entity = JsonUtil.getJsonToBean(moduleCrForm, ModuleEntity.class);
        if (entity.getUrlAddress() != null) {
            entity.setUrlAddress(entity.getUrlAddress().trim());
        }
        if (moduleService.isExistByFullName(entity, moduleCrForm.getCategory(), moduleCrForm.getSystemId())) {
            return ActionResult.fail(MsgCode.EXIST001.get());
        }
        if (moduleService.isExistByEnCode(entity, moduleCrForm.getCategory(), moduleCrForm.getSystemId())) {
            return ActionResult.fail(MsgCode.EXIST002.get());
        }
        moduleService.create(entity);
        return ActionResult.success(MsgCode.SU001.get());
    }

    /**
     * 更新系统功能
     *
     * @param id           主键值
     * @param moduleUpForm 实体对象
     * @return ignore
     */
    @Operation(summary = "更新系统功能")
    @Parameters({
            @Parameter(name = "id", description = "主键值", required = true),
            @Parameter(name = "moduleUpForm", description = "实体对象", required = true)
    })
    @SaCheckPermission("system.menu")
    @PutMapping("/{id}")
    public ActionResult update(@PathVariable("id") String id, @RequestBody @Valid ModuleUpForm moduleUpForm) {
        ModuleEntity entity = JsonUtil.getJsonToBean(moduleUpForm, ModuleEntity.class);
        // 判断如果是目录则不能修改类型
        ModuleEntity moduleEntity = moduleService.getInfo(id);
        if (moduleEntity != null && moduleEntity.getType() == 1 && entity.getType() != 1
                && moduleService.getList(moduleEntity.getId()).size() > 0) {
            return ActionResult.fail(MsgCode.SYS016.get());
        }
        entity.setId(id);
        if (entity.getUrlAddress() != null) {
            entity.setUrlAddress(entity.getUrlAddress().trim());
        }
        if (moduleService.isExistByFullName(entity, moduleUpForm.getCategory(), moduleUpForm.getSystemId())) {
            return ActionResult.fail(MsgCode.EXIST001.get());
        }
        if (moduleService.isExistByEnCode(entity, moduleUpForm.getCategory(), moduleUpForm.getSystemId())) {
            return ActionResult.fail(MsgCode.EXIST002.get());
        }
        boolean flag = moduleService.update(id, entity);
        if (!flag) {
            return ActionResult.fail(MsgCode.FA002.get());
        }
        return ActionResult.success(MsgCode.SU004.get());
    }

    /**
     * 删除系统功能
     *
     * @param id 主键值
     * @return ignore
     */
    @Operation(summary = "删除系统功能")
    @Parameters({
            @Parameter(name = "id", description = "主键值", required = true)
    })
    @SaCheckPermission("system.menu")
    @DeleteMapping("/{id}")
    public ActionResult delete(@PathVariable("id") String id) {
        ModuleEntity entity = moduleService.getInfo(id);
        if (entity != null) {
            List<ModuleEntity> list = moduleService.getList(false, new ArrayList<>(), new ArrayList<>()).stream()
                    .filter(t -> t.getParentId().equals(entity.getId())).collect(Collectors.toList());
            if (list.size() > 0) {
                return ActionResult.fail(MsgCode.SYS017.get());
            }
            moduleService.delete(entity);
            return ActionResult.success(MsgCode.SU003.get());
        }
        return ActionResult.fail(MsgCode.FA003.get());
    }

    /**
     * 更新菜单状态
     *
     * @param id 主键值
     * @return ignore
     */
    @Operation(summary = "更新菜单状态")
    @Parameters({
            @Parameter(name = "id", description = "主键值", required = true)
    })
    @SaCheckPermission("system.menu")
    @PutMapping("/{id}/Actions/State")
    public ActionResult upState(@PathVariable("id") String id) {
        ModuleEntity entity = moduleService.getInfo(id);
        if (entity != null) {
            if (entity.getEnabledMark() == null || "1".equals(String.valueOf(entity.getEnabledMark()))) {
                entity.setEnabledMark(0);
            } else {
                entity.setEnabledMark(1);
            }
            moduleService.update(id, entity);
            // 清除redis权限
            String cacheKey = cacheKeyUtil.getUserAuthorize() + UserProvider.getUser().getUserId();
            if (redisUtil.exists(cacheKey)) {
                redisUtil.remove(cacheKey);
            }
            return ActionResult.success(MsgCode.SU004.get());
        }
        return ActionResult.fail(MsgCode.FA002.get());
    }

    /**
     * 系统菜单导出功能
     *
     * @param id 接口id
     * @return ignore
     */
    @Operation(summary = "导出系统菜单数据")
    @Parameters({
            @Parameter(name = "id", description = "主键值", required = true)
    })
    @SaCheckPermission("system.menu")
    @GetMapping("/{id}/Actions/Export")
    public ActionResult exportFile(@PathVariable("id") String id) {
        DownloadVO downloadVO = moduleService.exportData(id);
        return ActionResult.success(downloadVO);
    }

    /**
     * 系统菜单导入功能
     *
     * @param systemId      系统id
     * @param multipartFile 文件
     * @param parentId      父级id
     * @param category      分类
     * @return ignore
     */
    @Operation(summary = "系统菜单导入功能")
    @Parameters({
            @Parameter(name = "systemId", description = "系统id", required = true),
    })
    @SaCheckPermission("system.menu")
    @PostMapping(value = "/{systemId}/Actions/Import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ActionResult importFile(@PathVariable("systemId") String systemId,
            @RequestPart("file") MultipartFile multipartFile,
            @RequestParam("parentId") String parentId,
            @RequestParam("category") String category,
            @RequestParam("type") Integer type) throws DataException {
        // 判断是否为.bm结尾
        if (FileUtil.existsSuffix(multipartFile, ModuleTypeEnum.SYSTEM_MODULE.getTableName())) {
            return ActionResult.fail(MsgCode.IMP002.get());
        }
        try {
            // 读取文件内容
            String fileContent = FileUtil.getFileContent(multipartFile);
            // 转model后导入
            ModuleExportModel exportModel = JsonUtil.getJsonToBean(fileContent, ModuleExportModel.class);
            ModuleEntity moduleEntity = exportModel.getModuleEntity();
            if (!category.equals(moduleEntity.getCategory())) {
                return ActionResult.fail(MsgCode.SYS018.get(category.toUpperCase()));
            }
            if ("App".equals(moduleEntity.getCategory()) && "-1".equals(parentId)) {
                return ActionResult.fail(MsgCode.SYS019.get());
            }
            // 设置系统id然后重新赋值
            moduleEntity.setSystemId(systemId);
            moduleEntity.setParentId(parentId);
            // 清空同步菜单记录 避免重复
            moduleEntity.setModuleId(null);
            moduleEntity.setCreatorTime(new Date());
            // String enCode = moduleEntity.getEnCode();
            // moduleEntity.setEnCode(moduleEntity.getEnCode() + "_" +
            // RandomUtil.getRandomCode());
            // if (moduleEntity.getType() == 3) {
            // moduleEntity.setUrlAddress(moduleEntity.getUrlAddress().replace(enCode,
            // moduleEntity.getEnCode()));
            // }
            exportModel.setModuleEntity(moduleEntity);
            return moduleService.importData(exportModel, type);
        } catch (Exception e) {
            throw new DataException(MsgCode.IMP004.get());
        }
    }

    // ------------------多租户调用
    /**
     * 通过租户id获取菜单
     *
     * @param tenantMenuModel 模型
     * @return ignore
     */
    @Operation(summary = "通过租户id获取菜单")
    @Parameters({
            @Parameter(name = "tenantMenuModel", description = "模型", required = true)
    })
    @NoDataSourceBind
    @PostMapping("/Tenant/Menu")
    public TenantMenuVO menu(@RequestBody TenantMenuModel tenantMenuModel) throws DataException {
        if (configValueUtil.isMultiTenancy()) {
            TenantDataSourceUtil.switchTenant(tenantMenuModel.getTenantId());
        }
        List<SystemEntity> systemEntityList = systemService.getList();
        List<String> ids = new ArrayList<>();
        if (Objects.nonNull(tenantMenuModel.getIds())) {
            ids = tenantMenuModel.getIds();
        }
        List<String> urlAddressList = new ArrayList<>();
        if (Objects.nonNull(tenantMenuModel.getIds())) {
            urlAddressList = tenantMenuModel.getUrlAddressList();
        }
        List<ModuleEntity> moduleEntityList = moduleService.getList(true, new ArrayList<>(), new ArrayList<>());
        TenantMenuVO module = module(systemEntityList, moduleEntityList, ids, urlAddressList);
        return module;
    }

    /**
     * 功能权限
     *
     * @param moduleEntityList 所有菜单
     * @param systemEntityList 所有应用
     * @return
     */
    private TenantMenuVO module(List<SystemEntity> systemEntityList, List<ModuleEntity> moduleEntityList,
            List<String> ids, List<String> urlAddressList) {
        TenantMenuVO vo = new TenantMenuVO();
        // 转树前所有数据
        List<TenantMenuTreeModel> moduleAllList = new ArrayList<>();
        List<TenantMenuTreeModel> systemList = JsonUtil.getJsonToList(systemEntityList, TenantMenuTreeModel.class);
        systemList.forEach(t -> t.setParentId("-1"));
        moduleAllList.addAll(systemList);
        Map<String, List<ModuleEntity>> moduleMap = moduleEntityList.stream().collect(Collectors.groupingBy(t -> {
            if ("Web".equals(t.getCategory())) {
                return "Web";
            } else {
                return "App";
            }
        }));
        List<ModuleEntity> webModuleList = moduleMap.get("Web") == null ? new ArrayList<>() : moduleMap.get("Web");
        List<ModuleEntity> appModuleList = moduleMap.get("App") == null ? new ArrayList<>() : moduleMap.get("App");
        Map<String, ModuleEntity> appModuleMap = appModuleList.stream()
                .collect(Collectors.toMap(ModuleEntity::getId, Function.identity()));
        Map<String, String> webIds = new HashMap<>(16);
        List<ModuleEntity> temWebList = webModuleList.stream().filter(t -> "-1".equals(t.getParentId()))
                .collect(Collectors.toList());
        temWebList.stream().filter(t -> "-1".equals(t.getParentId())).forEach(t -> {
            if (!webIds.containsKey(t.getSystemId())) {
                ModuleEntity webData = new ModuleEntity();
                webData.setId(t.getSystemId() + "1");
                t.setParentId(webData.getId());
                webData.setFullName("WEB菜单");
                webData.setIcon("icon-ym icon-ym-pc");
                webData.setParentId(t.getSystemId());
                webData.setSystemId(t.getSystemId());
                webModuleList.add(webData);
                webIds.put(t.getSystemId(), webData.getId());
            } else {
                t.setParentId(webIds.get(t.getSystemId()) + "");
            }
        });
        List<TenantMenuTreeModel> webReturnModuleList = JsonUtil.getJsonToList(webModuleList,
                TenantMenuTreeModel.class);
        moduleAllList.addAll(webReturnModuleList);
        // 处理App菜单
        List<ModuleEntity> temList = appModuleList.stream()
                .filter(t -> "-1".equals(t.getParentId()) && !YunzhupaasConst.MAIN_SYSTEM_CODE.equals(t.getEnCode()))
                .collect(Collectors.toList());
        Map<String, String> appIds = new HashMap<>(16);
        for (ModuleEntity appModuleEntity : temList) {
            if (StringUtil.isEmpty(appIds.get(appModuleEntity.getSystemId()))) {
                ModuleEntity appData = new ModuleEntity();
                appData.setId(appModuleEntity.getSystemId() + appModuleEntity.getSystemId() + "2");
                appModuleEntity.setParentId(appData.getId());
                appData.setFullName("APP菜单");
                appData.setIcon("icon-ym icon-ym-mobile");
                appData.setParentId(appModuleEntity.getSystemId());
                appData.setSystemId(appModuleEntity.getSystemId());
                appModuleList.add(appData);
                appIds.put(appModuleEntity.getSystemId(), appData.getId());
            } else {
                appModuleList.remove(appModuleEntity);
                ModuleEntity entity = appModuleMap.get(appModuleEntity.getId());
                entity.setParentId(appIds.get(appModuleEntity.getSystemId()));
                appModuleList.add(entity);
            }
        }
        List<TenantMenuTreeModel> appReturnModuleList = JsonUtil.getJsonToList(appModuleList,
                TenantMenuTreeModel.class);
        moduleAllList.addAll(appReturnModuleList);
        List<SumTree<TenantMenuTreeModel>> sumTrees = TreeDotUtils.convertListToTreeDot(moduleAllList);
        List<TenantMenuTreeReturnModel> data = new ArrayList<>();
        TenantMenuTreeReturnModel workFlowEnabled = new TenantMenuTreeReturnModel();
        workFlowEnabled.setId("-999");
        workFlowEnabled.setFullName("协同办公");
        data.add(workFlowEnabled);
        data.addAll(JsonUtil.getJsonToList(sumTrees, TenantMenuTreeReturnModel.class));
        vo.setList(data);
        List<String> allId = moduleAllList.stream().map(TenantMenuTreeModel::getId).collect(Collectors.toList());
        allId.add(workFlowEnabled.getId());
        vo.setAll(allId);
        List<String> ids0 = moduleService.getListByUrlAddress(ids, urlAddressList).stream().map(ModuleEntity::getId)
                .collect(Collectors.toList());
        List<String> selectorIds = allId.stream().filter(t -> !ids0.contains(t)).collect(Collectors.toList());
        if (ids.contains("-999")) {
            selectorIds.remove("-999");
        }
        vo.setIds(selectorIds);
        return vo;
    }

    /**
     * 通过租户id及菜单id获取菜单
     *
     * @param tenantMenuModel 模型
     * @return ignore
     */
    @Operation(summary = "通过租户id及菜单id获取菜单")
    @Parameters({
            @Parameter(name = "tenantMenuModel", description = "模型", required = true)
    })
    @NoDataSourceBind
    @PostMapping("/Tenant/MenuByIds")
    public Map MenuByIds(@RequestBody TenantMenuModel tenantMenuModel) throws DataException {
        if (configValueUtil.isMultiTenancy()) {
            TenantDataSourceUtil.switchTenant(tenantMenuModel.getTenantId());
        }
        List<ModuleEntity> list = moduleService.getList();
        return list.stream().collect(Collectors.toMap(ModuleEntity::getId, ModuleEntity::getUrlAddress));
    }

    /**
     * 获取在线开发“表单”和“流程”类型的菜单数据
     */
    @Operation(summary = "菜单获取表单列表")
    @GetMapping("/Selector/Form")
    @Parameters({
            @Parameter(name = "systemId", description = "系统id", required = false),
    })
    public ActionResult getFormList(ModulePagination pagination) {
        List<ModuleSelectorVo> list = moduleService.getFormMenuList(pagination);
        list.stream().forEach(t -> {
            t.setTypeName(Objects.equals(t.getType(), 3) ? "表单" : "流程");
            PropertyJsonModel model = JsonUtil.getJsonToBean(t.getPropertyJson(), PropertyJsonModel.class);
            if (Objects.equals(t.getType(), 3)) {
                t.setFormId(model.getModuleId());
            } else {
                t.setFlowId(model.getModuleId());
                t.setFormId(templateApi.getFormByFlowId(model.getModuleId()));
            }
        });
        PaginationVO paginationVO = JsonUtil.getJsonToBean(pagination, PaginationVO.class);
        return ActionResult.page(list, paginationVO);
    }

    /**
     * 报表发布菜单
     *
     * @return ignore
     */
    @Operation(summary = "报表发布菜单")
    @Parameters({
            @Parameter(name = "menuModel", description = "模型", required = true)
    })
    @PostMapping("/saveReportMenu")
    public ActionResult saveReportMenu(@RequestBody VisualMenuModel menuModel) {
        try {
            pubulishUtil.publishMenu(menuModel);
            return ActionResult.success();
        } catch (WorkFlowException e) {
            return ActionResult.fail(e.getMessage());
        }
    }

    /**
     * 报表发布菜单
     *
     * @return ignore
     */
    @Operation(summary = "获取报表发布菜单")
    @Parameters({
            @Parameter(name = "id", description = "主键值", required = true)
    })
    @PostMapping("/getReportMenu")
    public ActionResult getReportMenu(@RequestBody VisualMenuModel menuModel) {
        ModuleNameVO moduleNameVO = moduleService.getModuleNameList(menuModel.getId());
        return ActionResult.success(moduleNameVO);
    }

    /**
     * 获取系统菜单列表(下拉树形)
     */
    @Operation(summary = "获取系统菜单列表(下拉树形)")
    @GetMapping("/getSystemMenu")
    public ActionResult<List<MenuSelectAllVO>> getSystemMenu() {
        List<MenuSelectAllVO> systemMenu = moduleService.getSystemMenu(3, Arrays.asList(2, 4), Arrays.asList("web"));
        return ActionResult.success(systemMenu);
    }
}
