using AutoMapper;
using SqlSugar;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_DTO.System;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_ISystemServices;
using WIDESEAWCS_Model;
using WIDESEAWCS_Model.Models;

namespace WIDESEAWCS_SystemServices
{
    public class Sys_MenuService : ServiceBase<Sys_Menu, IRepository<Sys_Menu>>, ISys_MenuService
    {
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        private readonly IMapper _mapper;

        public Sys_MenuService(IRepository<Sys_Menu> BaseDal, IUnitOfWorkManage unitOfWorkManage, IMapper mapper) : base(BaseDal)
        {
            _unitOfWorkManage = unitOfWorkManage;
            _mapper = mapper;
        }

        /// <summary>
        /// 获取当前用户所有菜单与权限
        /// </summary>
        /// <returns></returns>
        public object GetCurrentMenuActionList()
        {
            object obj = GetMenuActionList(App.User.RoleId);
            if (obj is IEnumerable<object> list)
            {
                if (list.Any())
                {
                    return obj;
                }
                else
                {
                    return WebResponseContent.Instance.Error("未获取到菜单信息");
                }
            }
            return obj;
        }

        public List<MenuDTO> GetAllMenu()
        {
            List<Sys_Menu> menus = BaseDal.QueryData(x => x.Enable == 1 || x.Enable == 2).OrderByDescending(a => a.OrderNo).ThenByDescending(q => q.ParentId).ToList();
            List<MenuDTO> _menus = _mapper.Map<List<MenuDTO>>(menus);
            _menus.ForEach(x =>
            {
                x.MenuType ??= 0;
                if (!string.IsNullOrEmpty(x.Auth) && x.Auth.Length > 10)
                {
                    try
                    {
                        x.Actions = x.Auth.DeserializeObject<List<ActionDTO>>();
                    }
                    catch { }
                }
                x.Actions ??= new List<ActionDTO>();
            });
            string test = _menus.Serialize();
            return _menus;
        }

        public object GetSuperAdminMenu()
        {
            return GetAllMenu().Select(x =>
                  new
                  {
                      id = x.MenuId,
                      name = x.MenuName,
                      url = x.Url,
                      parentId = x.ParentId,
                      icon = x.Icon,
                      x.Enable,
                      x.TableName, // 2022.03.26增移动端加菜单类型
                      permission = x.Actions.Select(s => s.Value).ToArray()
                  }).ToList();
        }

        public object GetMenuByRoleId(int roleId)
        {
            var menu = from a in GetPermissions(roleId)
                       join b in GetAllMenu()
                       on a.MenuId equals b.MenuId
                       orderby b.OrderNo descending
                       select new
                       {
                           id = a.MenuId,
                           name = b.MenuName,
                           url = b.Url,
                           parentId = b.ParentId,
                           icon = b.Icon,
                           b.Enable,
                           b.TableName,
                           permission = a.UserAuthArr
                       };
            return menu.ToList();
        }

        /// <summary>
        /// 获取角色权限时通过安全字典锁定的角色id
        /// </summary>
        private static ConcurrentDictionary<string, object> objKeyValue = new ConcurrentDictionary<string, object>();

        public List<Permissions> GetPermissions(int roleId)
        {
            if (App.User.IsRoleIdSuperAdmin(roleId))
            {
                //2020.12.27增加菜单界面上不显示,但可以分配权限
                var permissions = BaseDal.QueryData(x => x.Enable == 1 || x.Enable == 2)
                    .Select(a => new Permissions
                    {
                        MenuId = a.MenuId,
                        ParentId = a.ParentId,
                        TableName = (a.TableName ?? "").ToLower(),
                        UserAuth = a.Auth,
                        MenuType = a.MenuType ?? 0
                    }).ToList();
                return MenuActionToArray(permissions);
            }

            //锁定每个角色,通过安全字典减少锁粒度,否则多个同时角色获取缓存会导致阻塞
            object objId = objKeyValue.GetOrAdd(roleId.ToString(), new object());
            //锁定每个角色
            lock (objId)
            {
                //没有redis/memory缓存角色的版本号或与当前服务器的角色版本号不同时,刷新缓存

                List<Permissions> _permissions = BaseDal.QueryTabs<Sys_Menu, Sys_RoleAuth, Permissions>((a, b) => new object[] { JoinType.Inner, a.MenuId == b.MenuId }, (a, b) => new Permissions { MenuId = a.MenuId, ParentId = a.ParentId, TableName = (a.TableName ?? "").ToLower(), MenuAuth = a.Auth, UserAuth = b.AuthValue ?? "", MenuType = a.MenuType ?? 0 }, (a, b) => b.RoleId == roleId, x => true);

                ActionToArray(_permissions);

                return _permissions;
            }
        }

        private List<Permissions> MenuActionToArray(List<Permissions> permissions)
        {
            permissions.ForEach(x =>
            {
                try
                {
                    x.UserAuthArr = string.IsNullOrEmpty(x.UserAuth)
                    ? new string[0]
                    : x.UserAuth.DeserializeObject<List<Sys_Actions>>().Select(s => s.Value).ToArray();
                }
                catch { }
                finally
                {
                    if (x.UserAuthArr == null)
                    {
                        x.UserAuthArr = new string[0];
                    }
                }
            });
            return permissions;
        }

        private List<Permissions> ActionToArray(List<Permissions> permissions)
        {
            permissions.ForEach(x =>
            {
                try
                {
                    var menuAuthArr = x.MenuAuth.DeserializeObject<List<Sys_Actions>>();
                    x.UserAuthArr = string.IsNullOrEmpty(x.UserAuth)
                    ? new string[0]
                    : x.UserAuth.Split(",").Where(c => menuAuthArr.Any(m => m.Value == c)).ToArray();

                }
                catch { }
                finally
                {
                    if (x.UserAuthArr == null)
                    {
                        x.UserAuthArr = new string[0];
                    }
                }
            });
            return permissions;
        }

        public object GetMenu(List<int> menuIds)
        {
            return BaseDal.QueryData(x => menuIds.Contains(x.MenuId)).Select(a =>
             new
             {
                 id = a.MenuId,
                 parentId = a.ParentId,
                 name = a.MenuName,
                 a.MenuType,
                 a.OrderNo
             }).OrderByDescending(a => a.OrderNo)
                .ThenByDescending(q => q.parentId).ToList();
        }

        public object GetTreeItem(int menuId)
        {
            var sysMenu = BaseDal.QueryData(x => x.MenuId == menuId)
                .Select(
                p => new
                {
                    p.MenuId,
                    p.ParentId,
                    p.MenuName,
                    p.Url,
                    p.Auth,
                    p.OrderNo,
                    p.Icon,
                    p.Enable,
                    // 2022.03.26增移动端加菜单类型
                    MenuType = p.MenuType ?? 0,
                    p.CreateDate,
                    p.Creater,
                    p.TableName,
                    p.ModifyDate
                }).FirstOrDefault();
            return sysMenu;
        }

        /// <summary>
        /// 根据角色ID获取菜单与权限
        /// </summary>
        /// <param name="roleId"></param>
        /// <returns></returns>
        public object GetMenuActionList(int roleId)
        {
            if (App.User.IsRoleIdSuperAdmin(roleId))
            {
                return GetSuperAdminMenu();
            }
            return GetMenuByRoleId(roleId);
        }


        public List<MenuDTO> GetUserMenuList(int roleId)
        {
            if (App.User.IsRoleIdSuperAdmin(roleId))
            {
                return GetAllMenu();
            }
            List<int> menuIds = GetPermissions(roleId).Select(x => x.MenuId).ToList();
            return GetAllMenu().Where(x => menuIds.Contains(x.MenuId)).ToList();
        }

        public List<ActionDTO> GetActions(int menuId, List<ActionDTO> menuActions, List<Permissions> permissions, int roleId)
        {
            if (App.User.IsRoleIdSuperAdmin(roleId))
            {
                return menuActions;
            }

            return menuActions.Where(p => permissions
                 .Exists(w => menuId == w.MenuId
                 && w.UserAuthArr.Contains(p.Value)))
                  .ToList();
        }

        /// <summary>
        /// 编辑修改菜单时,获取所有菜单
        /// </summary>
        /// <returns></returns>
        public object GetMenu()
        {
            if (App.User.IsRoleIdSuperAdmin(App.User.RoleId))
            {
                List<int> menuIds = BaseDal.QueryData().Select(x => x.MenuId).ToList();
                return GetMenu(menuIds);
            }
            else
            {
                List<int> menuIds = GetPermissions(App.User.RoleId).Select(x => x.MenuId).ToList();
                return GetMenu(menuIds);
            }
        }

        /// <summary>
        /// 新建或编辑菜单
        /// </summary>
        /// <param name="menu"></param>
        /// <returns></returns>
        public WebResponseContent Save(Sys_Menu menu)
        {
            WebResponseContent webResponse = new WebResponseContent();
            if (menu == null) return webResponse.Error("没有获取到提交的参数");
            if (menu.MenuId > 0 && menu.MenuId == menu.ParentId) return webResponse.Error("父级ID不能是当前菜单的ID");
            try
            {
                //webResponse = menu.ValidationEntity(x => new { x.MenuName, x.TableName });
                //if (!webResponse.Status) return webResponse;
                if (menu.TableName != "/" && menu.TableName != ".")
                {
                    // 2022.03.26增移动端加菜单类型判断
                    Sys_Menu sysMenu = BaseDal.QueryFirst(x => x.TableName == menu.TableName);
                    if (sysMenu != null)
                    {
                        sysMenu.MenuType ??= 0;
                        if (sysMenu.MenuType == menu.MenuType)
                        {
                            if ((menu.MenuId > 0 && sysMenu.MenuId != menu.MenuId)
                            || menu.MenuId <= 0)
                            {
                                return webResponse.Error($"视图/表名【{menu.TableName}】已被其他菜单使用");
                            }
                        }
                    }
                }
                bool _changed = false;
                if (menu.MenuId <= 0)
                {
                    int id = BaseDal.AddData(menu);
                    menu.MenuId = id;
                }
                else
                {
                    //2020.05.07新增禁止选择上级角色为自己
                    if (menu.MenuId == menu.ParentId)
                    {
                        return webResponse.Error($"父级id不能为自己");
                    } 
                    if (BaseDal.QueryFirst(x => x.ParentId == menu.MenuId && menu.ParentId == x.MenuId) != null)
                    {
                        return webResponse.Error($"不能选择此父级id,选择的父级id与当前菜单形成依赖关系");
                    }

                    _changed = BaseDal.QueryData(c => c.MenuId == menu.MenuId).Select(s => s.Auth).FirstOrDefault() != menu.Auth;

                    BaseDal.UpdateData(menu);
                }
                webResponse.OK("保存成功", menu);
            }
            catch (Exception ex)
            {
                webResponse.Error(ex.Message);
            }
            return webResponse;

        }

        public WebResponseContent DelMenu(int menuId)
        {
            WebResponseContent webResponse = new WebResponseContent();
            if(BaseDal.QueryFirst(x=>x.ParentId == menuId) != null)
            {
                return webResponse = WebResponseContent.Instance.Error("当前菜单存在子菜单,请先删除子菜单!");
            }
            BaseDal.DeleteDataById(menuId);

            return webResponse = WebResponseContent.Instance.OK("删除成功");
        }
    }
}