using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using XYY.Common.Standard;
using XYY.Core.Standard;
using XYY.Data.Standard;
using XYY.Model.Standard;
using XYY.Service.Standard.UserService.Model;

namespace XYY.Service.Standard.UserService
{
    public interface IUserService
    {
        Task<UserContent> GetUserContentAtApi(string token);
        Task<User_Info> Login(string account, string password);
        Task<LoginDto> LoginV2(string account, string password);

        Task<List<string>> GetUserRoleNames(int userId);
    }
    public class UserService : IUserService
    {
        private readonly IUserInfoRepository _userInfoRepository;
        private readonly IUserApiRepository _userApiRepository;
        private readonly IUserRoleRepository _userRoleRepository;
        private readonly IUserPermissionRepository _userPermissionRepository;
        private readonly IDistributedCache _cache;
        public UserService(
            IUserInfoRepository userInfoRepository,
            IUserApiRepository userApiRepository,
             IUserRoleRepository userRoleRepository,
             IDistributedCache cache,
              IUserPermissionRepository userPermissionRepository
             )
        {
            _userInfoRepository = userInfoRepository;
            _userApiRepository = userApiRepository;
            _userRoleRepository = userRoleRepository;
            _cache = cache;
            _userPermissionRepository = userPermissionRepository;
        }
        string keyBase = "userinfo";
        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="account">账号</param>
        /// <param name="password">密码</param>
        /// <returns></returns>
        public async Task<User_Info> Login(string account, string password)
        {
            Ensure.NotNullOrEmpty(account, "account");
            Ensure.NotNullOrEmpty(password, "password");

            var user = await _userInfoRepository.QueryAsync(x => (x.LoginAccount == account || x.Email == account) && x.LoginPassword == password);

            return user.FirstOrDefault();
        }

        public async Task<LoginDto> LoginV2(string account, string password)
        {
            Ensure.NotNullOrEmpty(account, "account");
            Ensure.NotNullOrEmpty(password, "password");

            password = MD5Util.Get(password);
            var user =await this.Login(account, password);
            if (user == null)
            {
                throw new Exception("用户名或密码错误");
            }
            if (!user.IsActive)
            {
                throw new Exception("该账号未激活或已被管理员关闭");
            }
            return await GetDto(user);
        }

        public async Task<List<string>> GetUserRoleNames(int userId)
        {
            var roles = await _userRoleRepository.GetUserRoles(userId);
            var roleNames = roles.Select(i => i.RoleName)?.ToList();
            return roleNames;
        }
            

        private async Task<LoginDto> GetDto(User_Info user)
        {
            var roles = await _userRoleRepository.GetUserRoles(user.Id);
            bool isAdmin = false;
            if (roles.Any(x => x.RoleName == "系统管理员"))
            {
                isAdmin = true;
            }
            var roleNames = roles.Select(i => i.RoleName)?.ToArray();

            int userId = user.Id;
            var result = await _userApiRepository.QueryAsync(i => i.UserId == userId);
            var api = result?.FirstOrDefault();
            if (api == null)
            {
                throw new Exception("User Token Not Found");
            }

            return new LoginDto()
            {
                Id = user.Id,
                Name = user.NickName,
                CustomerId = user.CustomerId,
                LoginAccount = user.LoginAccount,
                IsSuccess = true,
                IsAdmin = isAdmin,
                IsCustomer = user.CustomerId > 0,
                RoleNames = roleNames,
                Token = api.Token
            };
        }

        public async Task<UserContent> GetUserContentAtApi(string token)
        {
            string key = getTokenKey(token);
            string cacheData = await _cache.GetStringAsync(key);
            if (string.IsNullOrEmpty(cacheData))
            {
                var userInfo = await GetUserAtApi(token);
                var uc = await GetUserContent(userInfo);
                cacheData = Newtonsoft.Json.JsonConvert.SerializeObject(uc);
                await _cache.SetStringAsync(key, cacheData);
            }
            return Newtonsoft.Json.JsonConvert.DeserializeObject<UserContent>(cacheData);
        }

        private async Task<UserContent> GetUserContent(User_Info userInfo)
        {
            if (userInfo == null)
                return new UserContent { IsAuthorization = false };
            else
            {
                UserContent userContent = new UserContent
                {
                    IsAuthorization = true,
                    NiceName = userInfo.NickName,
                    CustomerId = userInfo.CustomerId,
                    Id = userInfo.Id
                };
                var roles = await GetUserRoles(userContent.Id);
                userContent.Roles = roles.Select(x => x.RoleName).ToList();
                var permissionTask = await GetPermissionByUserId(userContent.Id);
                userContent.PrivilegeUrl = permissionTask.Select(x => x.Href).Distinct().ToList();
                return userContent;
            }
        }

        public async Task<IEnumerable<User_Permission>> GetPermissionByUserId(int userId)
        {
            string sql = $@"SELECT c.* FROM dbo.User_UserRole(NOLOCK) a 
                            INNER JOIN dbo.User_RolePermission(NOLOCK) b ON a.RoleId=b.RoleId
                            INNER JOIN dbo.User_Permission(NOLOCK) c ON b.PermissionId = c.Id
                            WHERE c.IsEnable=1 AND a.UserId={userId}";
            return await _userPermissionRepository.QueryBySqlAsync(sql);
        }

        public async Task<User_Info> GetUserAtApi(string token)
        {
            token = token.Trim();
            string sql = @"select info.* from User_Info as info join User_API as api on info.Id = api.UserId and token=@token";
            var obj = await _userInfoRepository.QueryAsync(sql, new { token = token });
            return obj.FirstOrDefault();
        }

        /// <summary>
        /// 获取用户对应的角色
        /// </summary>
        /// <returns></returns>
        public async Task<List<User_Role>> GetUserRoles(int userId)
        {
            string sql = "Select UR.* from User_Role UR Join User_UserRole  URR on URR.UserId=" + userId + " and URR.RoleId = UR.Id";
            var r = await _userRoleRepository.QueryBySqlAsync(sql);
            return r.ToList();
        }

        private string getUserKey(int id)
        {
            return string.Concat(keyBase, "_", id.ToString());
        }

        /// <summary>
        /// 清除指定用户的Cache
        /// </summary>
        /// <param name="usreId"></param>
        public async Task ClareUserCache(int userId)
        {
            await _cache.RemoveAsync(getUserKey(userId));
        }

        private string getTokenKey(string token)
        {
            return string.Concat(keyBase, "_", token);
        }

        public async Task ClareUserCacheAsToken(string token)
        {
            await _cache.RemoveAsync(getTokenKey(token));
        }

        public async Task ClareUserCache()
        {
            await _cache.RemoveAsync(keyBase);
        }
    }
}
