using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.FriendlyException;
using Microsoft.AspNetCore.Http;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using Ewide.Core.Service;
using System;
using System.Data;

namespace Ewide.Core
{
    /// <summary>
    /// 用户管理
    /// </summary>
    public class UserManager : IUserManager, IScoped
    {
        private readonly IRepository<SysUser> _sysUserRep; // 用户表仓储   
        private readonly IRepository<SysRole> _sysRoleRep;
        private readonly IRepository<SysUserRole> _sysUserRoleRep;
        private readonly IRepository<SysEmp> _sysEmpRep;   // 员工表
        private readonly IRepository<SysOrg> _sysOrgRep;
        private readonly IRepository<SysRoleMenu> _sysRoleMenuRep;
        private readonly IRepository<SysMenu> _sysMenuRep;
        private readonly IRepository<SysUserDataScope> _sysUserDataScopeRep;
        private readonly IRepository<SysUserArea> _sysUserAreaRep;
        private readonly IRepository<SysRoleDataScope> _sysRoleDataRep;
        private readonly IRepository<SysRoleArea> _sysRoleAreaRep;
        private readonly IRepository<SysAreaCode> _sysAreaCodeRep;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly ISysCacheService _sysCacheService;

        public string UserId
        {
            get => _httpContextAccessor.HttpContext.User.FindFirst(ClaimConst.CLAINM_USERID)?.Value;
        }

        public string Account
        {
            get => _httpContextAccessor.HttpContext.User.FindFirst(ClaimConst.CLAINM_ACCOUNT)?.Value;
        }

        public string Name
        {
            get => _httpContextAccessor.HttpContext.User.FindFirst(ClaimConst.CLAINM_NAME)?.Value;
        }

        public bool SuperAdmin
        {
            get => _httpContextAccessor.HttpContext.User.FindFirst(ClaimConst.CLAINM_SUPERADMIN)?.Value == ((int)AdminType.SuperAdmin).ToString();
        }

        public SysUser User
        {
            get => _sysUserRep.Find(UserId);
        }

        public UserManager(
            IHttpContextAccessor httpContextAccessor,
            ISysCacheService sysCacheService,
            IRepository<SysUser> sysUserRep,
            IRepository<SysRole> sysRoleRep,
            IRepository<SysUserRole> sysUserRoleRep,
            IRepository<SysEmp> sysEmpRep,
            IRepository<SysOrg> sysOrgRep,
            IRepository<SysRoleMenu> sysRoleMenuRep,
            IRepository<SysMenu> sysMenuRep,
            IRepository<SysUserDataScope> sysUserDataScopeRep, IRepository<SysUserArea> sysUserAreaRep, IRepository<SysRoleDataScope> sysRoleDataRep, IRepository<SysRoleArea> sysRoleAreaRep, IRepository<SysAreaCode> sysAreaCodeRep)
        {
            _sysUserRep = sysUserRep;
            _sysRoleRep = sysRoleRep;
            _sysUserRoleRep = sysUserRoleRep;
            _sysEmpRep = sysEmpRep;
            _sysOrgRep = sysOrgRep;
            _httpContextAccessor = httpContextAccessor;
            _sysCacheService = sysCacheService;
            _sysRoleMenuRep = sysRoleMenuRep;
            _sysMenuRep = sysMenuRep;
            _sysUserDataScopeRep = sysUserDataScopeRep;
            _sysUserAreaRep = sysUserAreaRep;
            _sysRoleDataRep = sysRoleDataRep;
            _sysRoleAreaRep = sysRoleAreaRep;
            _sysAreaCodeRep = sysAreaCodeRep;
        }

        /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<SysUser> CheckUserAsync(string userId)
        {
            var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == userId, false);
            return user ?? throw Oops.Oh(ErrorCode.D1002);
        }

        /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <returns></returns>
        public async Task<SysUser> CheckUserAsync()
        {
            return await CheckUserAsync(UserId);
        }

        /// <summary>
        /// 获取用户员工信息
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<SysEmp> GetUserEmpInfo(string userId)
        {
            var emp = await _sysEmpRep.FirstOrDefaultAsync(u => u.Id == userId, false);
            return emp ?? throw Oops.Oh(ErrorCode.D1002);
        }

        /// <summary>
        /// 获取用户员工信息
        /// </summary>
        /// <returns></returns>
        public async Task<SysEmp> GetUserEmpInfo()
        {
            return await GetUserEmpInfo(UserId);
        }

        /// <summary>
        /// 获取用户部门信息
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<SysOrg> GetUserOrgInfo(string userId)
        {
            var emp = await GetUserEmpInfo(userId);
            var org = await _sysOrgRep.FirstOrDefaultAsync(u => u.Id == emp.OrgId, false);
            return org ?? throw Oops.Oh(ErrorCode.D1002);
        }

        /// <summary>
        /// 获取用户部门信息
        /// </summary>
        /// <returns></returns>
        public async Task<SysOrg> GetUserOrgInfo()
        {
            return await GetUserOrgInfo(UserId);
        }

        /// <summary>
        /// 获取用户角色Id列表
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<List<string>> GetUserRoleIdList(string userId)
        {
            var roleIds = await _sysUserRoleRep.DetachedEntities.Where(u => u.SysUserId == userId).Select(u => u.SysRoleId).ToListAsync();
            return roleIds;
        }

        /// <summary>
        /// 获取用户角色Id列表
        /// </summary>
        /// <returns></returns>
        public async Task<List<string>> GetUserRoleIdList()
        {
            return await GetUserRoleIdList(UserId);
        }

        /// <summary>
        /// 获取用户角色列表
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<List<SysRole>> GetUserRoleList(string userId)
        {
            var roleIds = await GetUserRoleIdList(userId);
            var roles = await _sysRoleRep.DetachedEntities.Where(u => roleIds.Contains(u.Id)).ToListAsync();
            return roles;
        }

        /// <summary>
        /// 获取用户角色列表
        /// </summary>
        /// <returns></returns>
        public async Task<List<SysRole>> GetUserRoleList()
        {
            return await GetUserRoleList(UserId);
        }

        public async Task<List<string>> GetLoginPermissionList()
        {
            var permissions = await _sysCacheService.GetPermission(UserId); // 先从缓存里面读取
            if (permissions == null || permissions.Count < 1)
            {
                var roleIdList = await GetUserRoleIdList();
                var menuIdList = await _sysRoleMenuRep.DetachedEntities
                                        .Where(u => roleIdList.Contains(u.SysRoleId))
                                        .Select(u => u.SysMenuId).ToListAsync();
                permissions = await _sysMenuRep.DetachedEntities.Where(u => menuIdList.Contains(u.Id))
                                                                .Where(u => u.Type == (int)MenuType.FUNCTION)
                                                                .Where(u => u.Status == (int)CommonStatus.ENABLE)
                                                                .Select(u => u.Permission).ToListAsync();
#if DEBUG
#else
                await _sysCacheService.SetPermission(UserId, permissions); // 缓存结果
#endif
            }
            return permissions;
        }

        public Task<List<string>> GetUserExtraDataScopeList()
        {
            return GetUserExtraDataScopeList(UserId);
        }

        public async Task<List<string>> GetUserExtraDataScopeList(string userId)
        {
            return await _sysUserDataScopeRep.DetachedEntities
                                 .Where(u => u.SysUserId == userId)
                                 .Select(u => u.SysOrgId).ToListAsync();
        }

        public Task<List<string>> GetUserExtraAreaScopeList()
        {
            return GetUserExtraAreaScopeList(UserId);
        }

        public async Task<List<string>> GetUserExtraAreaScopeList(string userId)
        {
            return await _sysUserAreaRep.DetachedEntities.Where(u => u.SysUserId == userId).Select(u => u.AreaCode).ToListAsync();
        }

        public Task<List<string>> GetRoleExtraDataScopeList(string roleId)
        {
            return _sysRoleDataRep.DetachedEntities.Where(u => u.SysRoleId == roleId).Select(u => u.SysOrgId).ToListAsync();
        }

        public Task<List<string>> GetRoleExtraAreaScopeList(string roleId)
        {
            return _sysRoleAreaRep.DetachedEntities.Where(u => u.SysRoleId == roleId).Select(u => u.AreaCode).ToListAsync();
        }
        public Task<List<string>> GetUserAllDataScopeList()
        {
            return GetUserAllDataScopeList(UserId);
        }
        public async Task<List<string>> GetDataScopeListByDataScopeType(int dataScopeType, string orgId)
        {
            var orgIdList = new List<string>();
            if (string.IsNullOrEmpty(orgId))
                return orgIdList;

            // 如果是范围类型是全部数据，则获取当前所有的组织架构Id
            if (dataScopeType == (int)DataScopeType.ALL)
            {
                orgIdList = await _sysOrgRep.DetachedEntities.Where(u => u.Status == (int)CommonStatus.ENABLE).Select(u => u.Id).ToListAsync();
            }
            // 如果范围类型是本部门及以下部门，则查询本节点和子节点集合，包含本节点
            else if (dataScopeType == (int)DataScopeType.DEPT_WITH_CHILD)
            {
                orgIdList = await _sysOrgRep.DetachedEntities
                                  .Where(u => u.Pids.Contains(orgId))
                                  .Select(u => u.Id).ToListAsync();
                orgIdList.Add(orgId);
            }
            // 如果数据范围是本部门，不含子节点，则直接返回本部门
            else if (dataScopeType == (int)DataScopeType.DEPT)
            {
                orgIdList.Add(orgId);
            }
            return orgIdList;
        }

        public async Task<List<string>> GetUserAllDataScopeList(string userId)
        {
            var dataScopes = await _sysCacheService.GetDataScope(userId); // 先从缓存里面读取
            if (dataScopes != null && dataScopes.Count > 0)
            {
                return dataScopes;
            }
            var orgId = await _sysEmpRep.DetachedEntities.Where(e => e.Id == userId).Select(u => u.OrgId).SingleAsync();
            var orgAreaCode = await _sysOrgRep.Where(o => o.Id == orgId).Select(o => o.AreaCode).SingleAsync();
            //获取用户额外授权数据
            var userExtraDataScope = await (from org in _sysOrgRep.DetachedEntities
                                            join ua in _sysUserAreaRep.DetachedEntities on org.AreaCode equals ua.AreaCode
                                            where ua.SysUserId == userId
                                            select org.Id).Concat(from ud in _sysUserDataScopeRep.DetachedEntities
                                                                  where ud.SysUserId == userId
                                                                  select ud.SysOrgId).ToListAsync();
            //获取用户所有角色
            //获取其他类型中最大的角色
            var areaScopeTypes = new[] { DataScopeType.AREA, DataScopeType.AREA_WITH_CHILD }.Cast<int>();
            var strongerDataScopeType = (int)DataScopeType.SELF;
            var strongerAreaType = (int)DataScopeType.SELF;

            //获取区域相关的角色类型中最大的区域角色
            var customDataScopeRoleIdList = new List<string>();
            var roleList = from role in _sysRoleRep.DetachedEntities
                           join ur in _sysUserRoleRep.DetachedEntities on role.Id equals ur.SysRoleId
                           where ur.SysUserId == userId
                           select role;
            foreach (var role in await roleList.ToListAsync())
            {
                if (role.DataScopeType == (int)DataScopeType.DEFINE)
                    customDataScopeRoleIdList.Add(role.Id);
                if ((role.DataScopeType == (int)DataScopeType.AREA || role.DataScopeType == (int)DataScopeType.AREA_WITH_CHILD) && strongerAreaType < role.DataScopeType)
                {
                    strongerAreaType = role.DataScopeType;
                }
                else if (role.DataScopeType <= strongerDataScopeType)
                    strongerDataScopeType = role.DataScopeType;
            }
            // 自定义数据范围的角色对应的数据范围
            var roleDataScopeIdList = await _sysRoleDataRep.DetachedEntities.Where(rd => customDataScopeRoleIdList.Contains(rd.SysRoleId)).Select(rd => orgId).ToListAsync();

            // 角色中拥有最大数据范围类型的数据范围
            var dataScopeIdList = await GetDataScopeListByDataScopeType(strongerDataScopeType, orgId);
            //角色区域数据范围
            var areaOrgIdList = new List<string>();
            if (strongerAreaType == (int)DataScopeType.AREA_WITH_CHILD)
                areaOrgIdList = await _sysOrgRep.DetachedEntities.Where(p => p.AreaCode.StartsWith(orgAreaCode)).Select(p => p.Id).ToListAsync();
            if (strongerAreaType == (int)DataScopeType.AREA)
                areaOrgIdList = await _sysOrgRep.DetachedEntities.Where(p => p.AreaCode == orgAreaCode).Select(p => p.Id).ToListAsync();
            //获取
            var scope = userExtraDataScope.Concat(roleDataScopeIdList).Concat(dataScopeIdList).Concat(areaOrgIdList).Distinct().ToList();
#if DEBUG
#else
            await _sysCacheService.SetDataScope(userId, scope);
#endif
            return scope;
        }
        /// <summary>
        /// 获取用户可以访问的区域权限
        /// </summary>
        /// <returns></returns>
        public Task<List<string>> GetUserAllAreaList()
        {
            return GetUserAllAreaList(UserId);
        }

        public async Task<List<string>> GetUserAllAreaList(string userId)
        {
            var orgId = await _sysEmpRep.DetachedEntities.Where(e => e.Id == userId).Select(u => u.OrgId).SingleAsync();
            var orgAreaCode = await _sysOrgRep.Where(o => o.Id == orgId).Select(o => o.AreaCode).SingleAsync();
            //本部门 或者 本部门区域    树结构只显示本级区域
            //本部门及以下 或者 本部门区域及以下 树结构显示本级和以下所有区域
            var extraUserArea = await GetUserExtraAreaScopeList(userId);
            var roles = await _sysUserRoleRep.DetachedEntities.Include(ur => ur.SysRole).Where(ur => ur.SysUserId == userId).Select(ur => ur.SysRole).ToListAsync();
            var customAreaRole = roles.Where(r => r.DataScopeType == (int)DataScopeType.DEFINE).Select(r => r.Id);
            var extraRoleArea = await _sysRoleAreaRep.DetachedEntities.Where(ra => customAreaRole.Contains(ra.SysRoleId)).Select(ra => ra.AreaCode).ToListAsync();
            var roleTypeArea = await GetUserDataScopeTypeAreaList(orgAreaCode, roles.Select(r => r.DataScopeType).ToList());
            var extraArea = await GetUserExtraAreaList(extraRoleArea.Concat(extraUserArea).Distinct().ToList());
            return extraArea.Concat(roleTypeArea).Distinct().ToList();
        }
        private async Task<List<string>> GetUserExtraAreaList(List<string> extraAreaCode)
        {
            var cachedAreaCode = await GetCachedAreaCode();
            return cachedAreaCode.Select(a => a.Code).Where(a => extraAreaCode.Any(e => a.StartsWith(e))).ToList();
        }
        private async Task<List<string>> GetUserDataScopeTypeAreaList(string orgAreaCode, List<int> roleDataTypeList)
        {
            var areaCode = await GetCachedAreaCode();
            if (roleDataTypeList.Any(r => r == (int)DataScopeType.ALL))
            {
                return  areaCode.Select(a => a.Code).ToList();
            }
            if (roleDataTypeList.Any(r => new[] { DataScopeType.DEPT_WITH_CHILD, DataScopeType.AREA_WITH_CHILD }.Cast<int>().Contains(r)))
            {
                return  areaCode.Where(a => a.Code.StartsWith(orgAreaCode)).Select(a => a.Code).ToList();
            }
            if (roleDataTypeList.Any(r => new[] { DataScopeType.DEPT, DataScopeType.AREA }.Cast<int>().Contains(r)))
            {
                return  areaCode.Where(a => a.Code == orgAreaCode).Select(a => a.Code).ToList();
            }
            return new List<string>();
        }
        private async Task<List<SysAreaCode>> GetCachedAreaCode()
        {
            var areaCodeList = await _sysCacheService.GetAreaCode();
            if (areaCodeList == null || areaCodeList.Count < 1)
            {
                areaCodeList = await _sysAreaCodeRep.DetachedEntities.ToListAsync();
            }
            return areaCodeList;
        }
    }
}