//----------SysMenu开始----------



using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Admin.Core.Common;
using Admin.Core.IRepository;
using Admin.Core.IRepository.ISys;
using Admin.Core.IService.ISys;
using Admin.Core.Model;
using Admin.Core.Model.Sys;
using AutoMapper;
using SqlSugar;

namespace Admin.Core.Service.Sys
{
    /// <summary>
    /// 菜单权限表Service
    /// </summary>	
    public partial class SysMenuService : BaseServices<SysMenu>, ISysMenuService
    {
        IBaseRepository<SysMenu> dal;
        private readonly ISysUserRoleRepository _sysUserRoleRepository;
        private readonly ISysRoleMenuRepository _sysRoleMenuRepository;
        IMapper _mapper;
        public SysMenuService(IBaseRepository<SysMenu> dal, ISysUserRoleRepository sysUserRoleRepository, ISysRoleMenuRepository sysRoleMenuRepository, IMapper mapper)
        {
            this.dal = dal;
            BaseDal = dal;
            _sysUserRoleRepository = sysUserRoleRepository;
            _sysRoleMenuRepository = sysRoleMenuRepository;
            _mapper = mapper;
        }

        /// <summary>
        /// 根据用户查询系统菜单列表
        /// </summary>
        /// <param name="userId"> 用户ID </param>
        /// <param name="pageQuery"> 查询参数 </param>
        /// <returns> 菜单列表 </returns>
        public async Task<List<SysMenu>> SelectMenuList(int userId, PageQuery<SysMenu> pageQuery)
        {
            List<SysMenu> menuList = new List<SysMenu>();
            if (!pageQuery.IsNotEmptyOrNull() || !pageQuery.Query.IsNotEmptyOrNull())
            {
                pageQuery = new PageQuery<SysMenu>();
                pageQuery.Query = new SysMenu();
            }

            Expression<Func<SysMenu, bool>> whereExpression = x => true;
            if (pageQuery.Query.MenuName.IsNotEmptyOrNull())
            {
                whereExpression = whereExpression.And(x => x.MenuName.Contains(pageQuery.Query.MenuName));
            }
            if (pageQuery.Query.Status.IsNotEmptyOrNull())
            {
                whereExpression = whereExpression.And(x => x.Status == pageQuery.Query.Status);
            }
            // 管理员显示所有菜单信息
            if (!UserView.IsAdmin(userId))
            {
                var roles = await _sysUserRoleRepository.QueryAsync(x => x.UserID == userId);
                var roleIds = roles.Select(x => x.RoleID).ToList();
                var menus = await _sysRoleMenuRepository.QueryAsync(x => roleIds.Contains(x.RoleID));
                var mendIds = menus.Select(x => x.MenuID).ToList();
                whereExpression = whereExpression.And(x => mendIds.Contains(x.MenuID));
            }

            menuList = await dal.QueryAsync(whereExpression, "OrderNum asc");
            return menuList;
        }

        /// <summary>
        /// 根据用户查询系统菜单列表
        /// </summary>
        /// <param name="userId"> 用户ID </param>
        /// <returns> 菜单列表 </returns>
        public async Task<List<SysMenu>> SelectMenuList(int userId)
        {
            Expression<Func<SysMenu, bool>> whereExpression = x => x.Status == SysConst.ENABLE;

            // 管理员显示所有菜单信息
            if (!UserView.IsAdmin(userId))
            {
                var roles = await _sysUserRoleRepository.QueryAsync(x => x.UserID == userId);
                var roleIds = roles.Select(x => x.RoleID).ToList();
                var menus = await _sysRoleMenuRepository.QueryAsync(x => roleIds.Contains(x.RoleID));
                var mendIds = menus.Select(x => x.MenuID).ToList();
                whereExpression = whereExpression.And(x => mendIds.Contains(x.MenuID));
            }

            var menuList = await dal.QueryAsync(whereExpression, "OrderNum asc");

            return menuList;
        }

        /// <summary>
        /// 根据用户ID查询权限
        /// </summary>
        /// <param name="userId"> 用户ID </param>
        /// <returns> 权限列表 </returns>
        public async Task<List<string>> SelectMenuPermsByUserId(int userId)
        {
            var data = await SelectMenuList(userId);
            return data.Select(x => x.Perms).ToList();
        }

        /// <summary>
        /// 根据用户ID查询菜单
        /// </summary>
        /// <param name="userId"> 用户名称 </param>
        /// <returns> 菜单列表 </returns>
        public async Task<List<MenuView>> SelectMenuTreeByUserId(int userId)
        {
            var data = await SelectMenuList(userId);
            var menus = _mapper.Map<List<MenuView>>(data);
            return GetChildPerms(menus, 0);
        }

        /// <summary>
        /// 根据角色ID查询菜单树信息
        /// </summary>
        /// <param name="roleId"> 角色ID </param>
        /// <returns> 选中菜单列表 </returns>
        public async Task<List<int>> SelectMenuListByRoleId(int roleId)
        {
            var roleMenus = await _sysRoleMenuRepository.QueryAsync(x => x.RoleID == roleId);
            return roleMenus.Select(x => (int)x.MenuID).ToList();
        }

        /// <summary>
        /// 构建前端路由所需要的菜单
        /// </summary>
        /// <param name="menus"> 菜单列表 </param>
        /// <returns> 路由列表 </returns>
        public List<RouterVo> BuildMenus(List<MenuView> menus)
        {
            List<RouterVo> routers = new List<RouterVo>();
            foreach (var menu in menus)
            {
                RouterVo router = new RouterVo();
                router.hidden = !(bool)menu.Visible;
                router.name = GetRouteName(menu);
                router.path = GetRouterPath(menu);
                router.component = GetComponent(menu);
                router.meta = new MetaVo()
                {
                    title = menu.MenuName,
                    icon = menu.Icon,
                    noCache = !(bool)menu.IsCache,
                    link = string.Empty
                };
                List<MenuView> cMenus = menu.Children;
                if (cMenus.Count > 0 && cMenus.Count > 0 && SysConst.TYPE_DIR.Equals(menu.MenuType))
                {
                    router.alwaysShow = true;
                    router.redirect = "noRedirect";
                    router.children = BuildMenus(cMenus);
                }
                else if (IsMenuFrame(menu))
                {
                    router.meta = null;
                    List<RouterVo> childrenList = new List<RouterVo>();
                    RouterVo children = new RouterVo();
                    children.path = menu.Path;
                    children.component = menu.Component;
                    children.name = StringHelper.Capitalize(menu.Path);
                    children.meta = new MetaVo
                    {
                        title = menu.MenuName,
                        icon = menu.Icon,
                        noCache = !(bool)menu.IsCache,
                        link = string.Empty
                    };
                    childrenList.Add(children);
                    router.children = childrenList;
                }
                else if (menu.ParentID.Value == 0 && IsInnerLink(menu))
                {
                    router.meta = new MetaVo
                    {
                        title = menu.MenuName,
                        icon = menu.Icon,
                        noCache = false,
                        link = string.Empty
                    };
                    router.path = "/inner";
                    List<RouterVo> childrenList = new List<RouterVo>();
                    RouterVo children = new RouterVo();
                    string routerPath = menu.Path;
                    children.path = routerPath;
                    children.component = SysConst.INNER_LINK;
                    children.name = StringHelper.Capitalize(routerPath);
                    children.meta = new MetaVo
                    {
                        title = menu.MenuName,
                        icon = menu.Icon,
                        noCache = false,
                        link = menu.Path
                    };
                    childrenList.Add(children);
                    router.children = childrenList;
                }
                routers.Add(router);
            }
            return routers;
        }

        /// <summary>
        /// 构建前端所需要树结构
        /// </summary>
        /// <param name="menus"> 菜单列表 </param>
        /// <returns> 树结构列表 </returns>
        public List<MenuView> BuildMenuTree(List<MenuView> menus)
        {
            List<MenuView> returnList = new List<MenuView>();
            List<int> tempList = new List<int>();
            foreach (var dept in menus)
            {
                tempList.Add(dept.MenuID);
            }
            for (IEnumerator<MenuView> iterator = menus.GetEnumerator(); iterator.MoveNext();)
            {
                MenuView menu = iterator.Current;
                // 如果是顶级节点, 遍历该父节点的所有子节点
                if (!tempList.Contains((int)menu.ParentID))
                {
                    RecursionFn(menus, menu);
                    returnList.Add(menu);
                }
            }
            if (returnList.Count == 0)
            {
                returnList = menus;
            }
            return returnList;
        }

        /// <summary>
        /// 构建前端所需要下拉树结构
        /// </summary>
        /// <param name="menus"> 菜单列表 </param>
        /// <returns> 下拉树结构列表 </returns>
        public List<TreeSelect> BuildMenuTreeSelect(List<SysMenu> menus)
        {
            var menuTreesList = _mapper.Map<List<MenuView>>(menus);
            var menuTrees = BuildMenuTree(menuTreesList);
            return _mapper.Map<List<TreeSelect>>(menuTrees);
        }

        /// <summary>
        /// 根据菜单ID查询信息
        /// </summary>
        /// <param name="menuId"> 菜单ID </param>
        /// <returns> 菜单信息 </returns>
        public async Task<SysMenu> SelectMenuById(int menuId)
        {
            return await dal.QueryByIdAsync(menuId);
        }

        /// <summary>
        /// 是否存在菜单子节点
        /// </summary>
        /// <param name="menuId"> 菜单ID </param>
        /// <returns> 结果 </returns>
        public async Task<bool> HasChildByMenuId(int menuId)
        {
            var result = await dal.QueryAsync(x => x.ParentID == menuId);
            return result.Count > 0;
        }

        /// <summary>
        /// 查询菜单使用数量
        /// </summary>
        /// <param name="menuId"> 菜单ID </param>
        /// <returns> 结果 </returns>
        public async Task<int> CheckMenuExistRole(int menuId)
        {
            var roleMenus = await _sysRoleMenuRepository.QueryAsync(x => x.MenuID == menuId);
            return roleMenus.Count;
        }

        /// <summary>
        /// 新增保存菜单信息
        /// </summary>
        /// <param name="menu"> 菜单信息 </param>
        /// <returns> 结果 </returns>
        public async Task<int> InsertMenu(SysMenu menu)
        {
            menu.CreateTime = DateTime.Now;
            menu.UpdateTime = DateTime.Now;
            if (!menu.ParentID.IsNotEmptyOrNull())
            {
                menu.ParentID = 0;
            }

            return await dal.AddAsync(menu); ;
        }

        /// <summary>
        /// 修改保存菜单信息
        /// </summary>
        /// <param name="menu"> 菜单信息 </param>
        /// <returns> 结果 </returns>
        public async Task<bool> UpdateMenu(SysMenu menu)
        {
            var list = await dal.QueryAsync();
            var updates = new List<SysMenu>();

            GetChilds(list, menu.MenuID, ref updates);
            updates.Add(menu);
            updates.ForEach(x =>
            {
                x.Status = menu.Status;
                x.UpdateBy = menu.UpdateBy;
                x.UpdateTime = DateTime.Now;
            });
            return await dal.UpdateAsync(updates);
        }

        /// <summary>
        /// 删除菜单管理信息
        /// </summary>
        /// <param name="menuId"> 菜单ID </param>
        /// <returns> 结果 </returns>
        public async Task<bool> DeleteMenuById(int menuId)
        {
            return await dal.DeleteByIdAsync(menuId);
        }

        /// <summary>
        /// 校验菜单名称是否唯一
        /// </summary>
        /// <param name="menu"> 菜单信息 </param>
        /// <returns> 结果 </returns>
        public async Task<bool> CheckMenuNameUnique(SysMenu menu)
        {
            var info = await dal.QueryAsync(x => x.MenuName == menu.MenuName && x.MenuID != menu.MenuID);
            return info.Count == 0;
        }

        /// <summary>
        /// 获取路由名称
        /// </summary>
        /// <param name="menu"> 菜单信息 </param>
        /// <returns> 路由名称 </returns>
        public string GetRouteName(SysMenu menu)
        {
            string routerName = menu.Path;
            // 非外链并且是一级目录(类型为目录)
            if (IsMenuFrame(menu))
            {
                routerName = string.Empty;
            }
            if (routerName.IsNotEmptyOrNull())
            {
                routerName = routerName.Substring(0, 1).ToUpper() + routerName.Substring(1);
            }
            return routerName;
        }

        /// <summary>
        /// 获取路由地址
        /// </summary>
        /// <param name="menu"> 菜单信息 </param>
        /// <returns> 路由地址 </returns>
        public string GetRouterPath(SysMenu menu)
        {
            string routerPath = menu.Path;
            // 内链打开外网方式
            if (menu.ParentID.Value != 0 && IsInnerLink(menu))
            {

            }
            // 非外链并且是一级目录(类型为目录)
            if (0 == menu.ParentID.Value && SysConst.TYPE_DIR.Equals(menu.MenuType) && SysConst.NO_FRAME.Equals(menu.IsFrame))
            {
                routerPath = "/" + menu.Path;
            }
            // 非外链并且是一级目录(类型为菜单)
            else if (IsMenuFrame(menu))
            {
                routerPath = "/";
            }
            return routerPath;
        }

        /// <summary>
        /// 获取组件信息
        /// </summary>
        /// <param name="menu"> 菜单信息 </param>
        /// <returns> 组件信息 </returns>
        public string GetComponent(SysMenu menu)
        {
            string component = SysConst.LAYOUT;
            if (menu.Component.IsNotEmptyOrNull() && !IsMenuFrame(menu))
            {
                component = menu.Component;
            }
            else if (menu.ParentID.Value != 0 && IsInnerLink(menu))
            {
                component = SysConst.INNER_LINK;
            }
            else if (IsParentView(menu))
            {
                component = SysConst.PARENT_VIEW;
            }
            return component;
        }

        /// <summary>
        /// 是否为菜单内部跳转
        /// </summary>
        /// <param name="menu"> 菜单信息 </param>
        /// <returns> 结果 </returns>
        public bool IsMenuFrame(SysMenu menu)
        {
            return menu.ParentID.Value == 0 && SysConst.TYPE_MENU.Equals(menu.MenuType) && menu.IsFrame.Equals(SysConst.NO_FRAME);
        }

        /// <summary>
        /// 是否为内链组件
        /// </summary>
        /// <param name="menu"> 菜单信息 </param>
        /// <returns> 结果 </returns>
        public bool IsInnerLink(SysMenu menu)
        {
            return menu.IsFrame.Equals(SysConst.NO_FRAME) && StringHelper.IsUrl(menu.Path);
        }

        /// <summary>
        /// 是否为parent_view组件
        /// </summary>
        /// <param name="menu"> 菜单信息 </param>
        /// <returns> 结果 </returns>
        public bool IsParentView(SysMenu menu)
        {
            return menu.ParentID.Value != 0 && SysConst.TYPE_DIR.Equals(menu.MenuType);
        }

        /// <summary>
        /// 根据子节点的ID获取所有父节点
        /// </summary>
        /// <param name="list"> 分类表 </param>
        /// <param name="childrenId"> 传入的子节点ID </param>
        /// <returns> String </returns>
        public List<SysMenu> GetParents(List<SysMenu> list, int childrenId, ref List<SysMenu> returnList)
        {
            foreach (var item in list)
            {
                if (item.MenuID == childrenId && item.ParentID > 0)
                {
                    returnList.Add(item);
                    GetParents(list, (int)item.ParentID, ref returnList);
                }
                else if (item.MenuID == childrenId && item.ParentID == 0)
                {
                    returnList.Add(item);
                }
            }
            return returnList;
        }

        /// <summary>
        /// 根据父节点的ID获取所有子节点
        /// </summary>
        /// <param name="list"> 分类表 </param>
        /// <param name="parentId"> 传入的父节点ID </param>
        /// <returns> String </returns>
        public List<SysMenu> GetChilds(List<SysMenu> list, int parentId, ref List<SysMenu> returnList)
        {
            foreach (var item in list)
            {
                if (item.ParentID == parentId)
                {
                    returnList.Add(item);
                    GetChilds(list, item.MenuID, ref returnList);
                }
            }
            return returnList;
        }

        /// <summary>
        /// 根据父节点的ID获取所有子节点
        /// </summary>
        /// <param name="list"> 分类表 </param>
        /// <param name="parentId"> 传入的父节点ID </param>
        /// <returns> String </returns>
        public List<MenuView> GetChildPerms(List<MenuView> list, int parentId)
        {
            List<MenuView> returnList = new List<MenuView>();
            for (IEnumerator<MenuView> iterator = list.GetEnumerator(); iterator.MoveNext();)
            {
                MenuView t = iterator.Current;
                // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
                if (t.ParentID == parentId)
                {
                    RecursionFn(list, t);
                    returnList.Add(t);
                }
            }
            return returnList;
        }

        /// <summary>
        /// 递归列表
        /// </summary>
        /// <param name="list"> </param>
        /// <param name="t"> </param>
        private void RecursionFn(List<MenuView> list, MenuView t)
        {
            // 得到子节点列表
            List<MenuView> childList = GetChildList(list, t);
            t.Children = childList;
            foreach (MenuView tChild in childList)
            {
                if (HasChild(list, tChild))
                {
                    RecursionFn(list, tChild);
                }
            }
        }

        /// <summary>
        /// 得到子节点列表
        /// </summary>
        private List<MenuView> GetChildList(List<MenuView> list, MenuView t)
        {
            List<MenuView> tlist = new List<MenuView>();
            IEnumerator<MenuView> it = list.GetEnumerator();
            while (it.MoveNext())
            {
                MenuView n = it.Current;
                if (n.ParentID.Value == t.MenuID)
                {
                    tlist.Add(n);
                }
            }
            return tlist;
        }

        /// <summary>
        /// 判断是否有子节点
        /// </summary>
        private bool HasChild(List<MenuView> list, MenuView t)
        {
            return GetChildList(list, t).Count > 0 ? true : false;
        }
    }

}


//----------SysMenu结束----------