using Furion.DatabaseAccessor.Extensions;
using YBEE.EQM.Core;

namespace YBEE.EQM.Application
{
    /// <summary>
    /// 菜单服务
    /// </summary>
    public class SysMenuService : ISysMenuService, ITransient
    {
        private readonly IRepository<SysMenu> _menuRep;
        private readonly ISysRoleUserService _roleUserService;
        private readonly ISysRoleMenuService _roleMenuService;
        private readonly ICacheService _cacheService;
        public SysMenuService(IRepository<SysMenu> menuRep, ISysRoleUserService roleUserService, ISysRoleMenuService roleMenuService, ICacheService cacheService)
        {
            _menuRep = menuRep;
            _roleUserService = roleUserService;
            _roleMenuService = roleMenuService;
            _cacheService = cacheService;
        }

        #region 私有方法
        /// <summary>
        /// 创建Pids格式
        /// 如果pid是0顶级节点，pids就是 [0];
        /// 如果pid不是顶级节点，pids就是 pid菜单的 pids + [pid] + ,
        /// </summary>
        /// <param name="pid"></param>
        /// <returns></returns>
        private async Task<string> CreateNewPids(long pid)
        {
            if (pid == 0L)
            {
                return "[0],";
            }
            else
            {
                var pmenu = await _menuRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == pid);
                return pmenu.Pids + "[" + pid + "],";
            }
        }
        /// <summary>
        /// 增加和编辑时检查参数
        /// </summary>
        /// <param name="input"></param>
        private static void CheckMenuParam(SysMenuInput input)
        {
            var type = input.MenuType;
            var router = input.Router;
            var permission = input.Permission;
            var openType = input.OpenType;

            if (type.Equals((int)MenuType.FOLDER))
            {
                if (string.IsNullOrEmpty(router)) { throw Oops.Oh(ErrorCode.E8102); }
            }
            else if (type.Equals((int)MenuType.MENU))
            {
                if (string.IsNullOrEmpty(router)) { throw Oops.Oh(ErrorCode.E8102); }
                if (string.IsNullOrEmpty(openType.ToString())) { throw Oops.Oh(ErrorCode.E8103); }
            }
            else if (type.Equals((int)MenuType.BUTTON))
            {
                if (string.IsNullOrEmpty(permission)) { throw Oops.Oh(ErrorCode.E8104); }
                if (!permission.Contains('.')) { throw Oops.Oh(ErrorCode.E8105); }
                // 判断该资源是否存在
                //permission = ":" + permission;
                //var urlSet = resourceCache.getAllResources();
                //if (!urlSet.Contains(permission.Replace(":","/")))
                //    throw Oops.Oh(ErrorCode.meu1005);
            }
        }
        #endregion

        /// <summary>
        /// 添加菜单
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task Add(AddSysMenuInput input)
        {
            var isExist = await _menuRep.DetachedEntities.AnyAsync(u => u.Code == input.Code); // u.Name == input.Name
            if (isExist)
            {
                throw Oops.Oh(ErrorCode.E8101);
            }

            // 校验参数
            CheckMenuParam(input.Adapt<SysMenuInput>());

            var menu = input.Adapt<SysMenu>();
            menu.Pids = await CreateNewPids(input.Pid);
            menu.Status = CommonStatus.ENABLE;
            await menu.InsertAsync();

            // 清除缓存
            await _cacheService.DelByPatternAsync(CommonConst.CACHE_KEY_MENU);
            await _cacheService.DelByPatternAsync(CommonConst.CACHE_KEY_PERMISSION);
        }
        /// <summary>
        /// 更新菜单
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task Update(UpdateSysMenuInput input)
        {
            // Pid和Id不能一致，一致会导致无限递归
            if (input.Id == input.Pid)
            {
                throw Oops.Oh(ErrorCode.E8107);
            }

            var isExist = await _menuRep.DetachedEntities.AnyAsync(u => u.Code == input.Code && u.Id != input.Id); // u.Name == input.Name
            if (isExist)
            {
                throw Oops.Oh(ErrorCode.E8101);
            }

            // 校验参数
            CheckMenuParam(input.Adapt<SysMenuInput>());
            // 如果是编辑，父id不能为自己的子节点
            var childIdList = await _menuRep.DetachedEntities.Where(u => u.Pids.Contains(input.Id.ToString()))
                                                                .Select(u => u.Id).ToListAsync();
            if (childIdList.Contains(input.Pid))
                throw Oops.Oh(ErrorCode.E8107);

            var oldMenu = await _menuRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == input.Id);

            // 生成新的pids
            var newPids = await CreateNewPids(input.Pid);

            // 是否更新子节点的pids的标识
            var updateSubPidsFlag = input.Pid != oldMenu.Pid;

            // 开始更新所有子节点的配置
            if (updateSubPidsFlag)
            {
                // 查找所有叶子节点，包含子节点的子节点
                var menuList = await _menuRep.Where(u => EF.Functions.Like(u.Pids, $"%{oldMenu.Id}%")).ToListAsync();
                // 更新所有子节点的应用为当前菜单的应用
                if (menuList.Count > 0)
                {
                    // 更新所有子节点的pids
                    if (updateSubPidsFlag)
                    {
                        menuList.ForEach(u =>
                        {
                            // 子节点pids组成 = 当前菜单新pids + 当前菜单id + 子节点自己的pids后缀
                            var oldParentCodesPrefix = oldMenu.Pids + "[" + oldMenu.Id + "],";
                            var oldParentCodesSuffix = u.Pids[oldParentCodesPrefix.Length..];
                            var menuParentCodes = newPids + "[" + oldMenu.Id + "]," + oldParentCodesSuffix;
                            u.Pids = menuParentCodes;
                        });
                    }
                }
            }

            // 更新当前菜单
            oldMenu = input.Adapt<SysMenu>();
            oldMenu.Pids = newPids;
            await oldMenu.UpdateAsync(ignoreNullValues: true);

            // 清除缓存
            await _cacheService.DelByPatternAsync(CommonConst.CACHE_KEY_MENU);
            await _cacheService.DelByPatternAsync(CommonConst.CACHE_KEY_PERMISSION);
        }
        /// <summary>
        /// 删除菜单
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task Del(DeleteSysMenuInput input)
        {
            var childIdList = await _menuRep.DetachedEntities.Where(u => u.Pids.Contains(input.Id.ToString()))
                                                                .Select(u => u.Id).ToListAsync();
            childIdList.Add(input.Id);

            var menus = await _menuRep.Where(u => childIdList.Contains(u.Id)).ToListAsync();
            await _menuRep.DeleteAsync(menus);

            // 级联删除该菜单及子菜单对应的角色-菜单表信息
            //await _sysRoleMenuService.DeleteRoleMenuListByMenuIdList(childIdList);

            // 清除缓存
            await _cacheService.DelByPatternAsync(CommonConst.CACHE_KEY_MENU);
            await _cacheService.DelByPatternAsync(CommonConst.CACHE_KEY_PERMISSION);
        }
        /// <summary>
        /// 获取菜单列表
        /// </summary>
        /// <returns></returns>
        public async Task<List<SysMenuOutput>> GetAllList()
        {
            var items = await _menuRep.DetachedEntities.Where(u => u.Status == CommonStatus.ENABLE)
                                                        .OrderBy(u => u.Sort)
                                                        .ProjectToType<SysMenuOutput>()
                                                        .ToListAsync();
            return items;
        }
        /// <summary>
        /// 获取所有菜单（树形）
        /// </summary>
        /// <returns></returns>
        public async Task<List<SysMenuOutput>> GetAllTreeList()
        {
            var menus = await _menuRep.DetachedEntities.Where(u => u.Status == CommonStatus.ENABLE)
                                                       .ProjectToType<SysMenuOutput>()
                                                       .ToListAsync();
            return new TreeBuildUtil<SysMenuOutput>().Build(menus);
        }

        /// <summary>
        /// 获取用户权限(按钮权限标识集合)
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<List<string>> GetLoginPermissionList(int userId)
        {
            var permissions = await _cacheService.GetPermission(userId); // 先从缓存里面读取
            if (permissions == null || permissions.Count < 1)
            {
                if (!CurrentSysUserInfo.IsSuperAdmin && userId != 0)
                {
                    var roleIdList = await _roleUserService.GetUserRoleIdList(userId);
                    var menuIdList = await _roleMenuService.GetRoleMenuIdList(roleIdList);
                    permissions = await _menuRep.DetachedEntities.Where(u => menuIdList.Contains(u.Id))
                                                                    .Where(u => u.MenuType == MenuType.BUTTON)
                                                                    .Where(u => u.Status == CommonStatus.ENABLE)
                                                                    .Select(u => u.Permission).ToListAsync();
                }
                else
                {
                    permissions = await _menuRep.DetachedEntities
                                                   .Where(u => u.MenuType == MenuType.BUTTON)
                                                   .Where(u => u.Status == CommonStatus.ENABLE)
                                                   .Select(u => u.Permission).ToListAsync();
                }
                await _cacheService.SetPermission(userId, permissions); // 缓存结果
            }
            return permissions;
        }

        /// <summary>
        /// 获取所有权限(按钮权限标识集合)
        /// </summary>
        /// <returns></returns>
        public async Task<List<string>> GetAllPermissionList()
        {
            return await GetLoginPermissionList(0);
        }

        /// <summary>
        /// 获取前端可使用的菜单列表
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<List<AntMenuOutput>> GetLoginAntMenus(int userId)
        {
            var items = await _cacheService.GetMenu(userId); // 先从缓存里面读取
            if (items == null || items.Count < 1)
            {
                var sysMenuList = new List<SysMenu>();
                // 管理员则展示所有系统菜单
                if (CurrentSysUserInfo.IsSuperAdmin)
                {
                    sysMenuList = await _menuRep.DetachedEntities
                                                   .Where(u => u.Status == CommonStatus.ENABLE && u.Visible == true)
                                                   .Where(u => u.MenuType != MenuType.BUTTON)
                                                   .OrderBy(u => u.Sort).ThenBy(u => u.Id).ToListAsync();
                }
                else
                {
                    // 非管理员则获取自己角色所拥有的菜单集合
                    var roleIdList = await _roleUserService.GetUserRoleIdList(userId);
                    var menuIdList = await _roleMenuService.GetRoleMenuIdList(roleIdList);
                    sysMenuList = await _menuRep.DetachedEntities
                                                   .Where(u => menuIdList.Contains(u.Id))
                                                   .Where(u => u.Status == CommonStatus.ENABLE && u.Visible == true)
                                                   .Where(u => u.MenuType != MenuType.BUTTON)
                                                   .OrderBy(u => u.Sort).ThenBy(u => u.Id).ToListAsync();
                }
                // 转换成登录菜单
                items = sysMenuList.Select(u => new AntMenuOutput
                {
                    Id = u.Id,
                    Pid = u.Pid,
                    Path = u.OpenType == MenuOpenType.OUTER ? u.Link : u.Router,
                    Name = u.Code,
                    Component = u.Component,
                    Title = u.Name,
                    Icon = u.Icon,
                    Visible = u.Visible,
                    Link = u.Link,
                    Target = u.OpenType == MenuOpenType.OUTER ? "_blank" : "",
                }).ToList();
                await _cacheService.SetMenu(userId, items); // 缓存结果
            }
            return items;
        }
    }
}