using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Transactions;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Authorization.Users;
using Abp.Domain.Entities;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.IdentityFramework;
using Abp.Linq.Extensions;
using Abp.Localization;
using Abp.Runtime.Session;
using Abp.UI;
using Mapster;
using YGNT.Exam.Authorization;
using YGNT.Exam.Authorization.Accounts;
using YGNT.Exam.Authorization.Roles;
using YGNT.Exam.Authorization.Users;
using YGNT.Exam.Roles.Dto;
using YGNT.Exam.Users.Dto;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using YGNT.Infrastructure.Extension;

namespace YGNT.Exam.Users
{
    [AbpAuthorize()]
    public class UserAppService : AsyncCrudAppService<User, UserDto, long, PagedUserResultRequestDto, CreateUserDto, UserDto>, IUserAppService
    {
        private readonly UserManager _userManager;
        private readonly RoleManager _roleManager;
        private readonly IRepository<Role> _roleRepository;
        private readonly IPasswordHasher<User> _passwordHasher;
        private readonly IAbpSession _abpSession;
        private readonly IUserManagerAppService _userManagerAppService;
        private readonly LogInManager _logInManager;

        public UserAppService(
            IRepository<User, long> repository,
            UserManager userManager,
            RoleManager roleManager,
            IRepository<Role> roleRepository,
            IPasswordHasher<User> passwordHasher,
            IAbpSession abpSession,
            LogInManager logInManager, IUserManagerAppService userManagerAppService)
            : base(repository)
        {
            CreatePermissionName = PermissionNames.Pages_Users;
            UpdatePermissionName = PermissionNames.Pages_Users;
            DeletePermissionName = PermissionNames.Pages_Users;
            _userManager = userManager;
            _roleManager = roleManager;
            _roleRepository = roleRepository;
            _passwordHasher = passwordHasher;
            _abpSession = abpSession;
            _logInManager = logInManager;
            _userManagerAppService = userManagerAppService;
        }

        public override async Task<UserDto> CreateAsync(CreateUserDto input)
        {
            CheckCreatePermission();

            var user = ObjectMapper.Map<User>(input);

            user.TenantId = AbpSession.TenantId;
            user.IsEmailConfirmed = true;

            var isExist = await Repository.AnyAsync(x =>
                x.PhoneNumber == user.PhoneNumber && x.TenantId == user.TenantId);
            if (isExist)
                throw new UserFriendlyException($"手机号:{user.PhoneNumber}已存在!");

            await _userManager.InitializeOptionsAsync(AbpSession.TenantId);

            CheckErrors(await _userManager.CreateAsync(user, input.Password));

            if (input.RoleNames != null)
            {
                CheckErrors(await _userManager.SetRolesAsync(user, input.RoleNames));
            }

            CurrentUnitOfWork.SaveChanges();

            return MapToEntityDto(user);
        }

        public override async Task<UserDto> UpdateAsync(UserDto input)
        {
            CheckUpdatePermission();

            var user = await _userManager.GetUserByIdAsync(input.Id);

            if (user.UserName == AbpUserBase.AdminUserName)
            {
                if (!input.IsActive)
                    throw new UserFriendlyException("管理员账号不能被禁用");
                if (input.RoleNames != null && input.RoleNames.All(x => x != StaticRoleNames.Tenants.Admin))
                    throw new UserFriendlyException("禁止取消管理员账号的管理员角色");

            }

            MapToEntity(input, user);

            CheckErrors(await _userManager.UpdateAsync(user));

            if (input.RoleNames != null)
            {
                CheckErrors(await _userManager.SetRolesAsync(user, input.RoleNames));
            }

            return await GetAsync(input);
        }

        public override async Task DeleteAsync(EntityDto<long> input)
        {
            var user = await _userManager.GetUserByIdAsync(input.Id);
            if (user.UserName == AbpUserBase.AdminUserName)
                throw new UserFriendlyException("禁止删除管理员账号");
            await _userManager.DeleteAsync(user);
        }

        public async Task<ListResultDto<RoleDto>> GetRoles()
        {
            var roles = await _roleRepository.GetAllListAsync();
            return new ListResultDto<RoleDto>(ObjectMapper.Map<List<RoleDto>>(roles));
        }

        public async Task ChangeLanguage(ChangeUserLanguageDto input)
        {
            await SettingManager.ChangeSettingForUserAsync(
                AbpSession.ToUserIdentifier(),
                LocalizationSettingNames.DefaultLanguage,
                input.LanguageName
            );
        }

        protected override User MapToEntity(CreateUserDto createInput)
        {
            var user = ObjectMapper.Map<User>(createInput);
            user.SetNormalizedNames();
            return user;
        }

        protected override void MapToEntity(UserDto input, User user)
        {
            ObjectMapper.Map(input, user);
            user.SetNormalizedNames();
        }

        protected override UserDto MapToEntityDto(User user)
        {
            var roleIds = user.Roles.Select(x => x.RoleId).ToArray();

            var roles = _roleManager.Roles.Where(r => roleIds.Contains(r.Id)).Select(r =>
                r.Adapt<UserRoleDto>());

            var userDto = base.MapToEntityDto(user);
            userDto.RoleNames = roles.Select(x => x.NormalizedName).ToArray();
            userDto.DisplayNames = roles.Select(x => x.DisplayName).ToArray();

            using (var unitOfWork = UnitOfWorkManager.Begin(TransactionScopeOption.Suppress))
            {
                var userDisciplines = _userManagerAppService.GetUserDisciplineAsync(user.Id).Result;
                unitOfWork.Complete();
                userDto.UserDisciplines = userDisciplines;
            }


            return userDto;
        }

        protected override IQueryable<User> CreateFilteredQuery(PagedUserResultRequestDto input)
        {
            return Repository.GetAllIncluding(x => x.Roles)
                .WhereIf(!input.Keyword.IsNullOrWhiteSpace(), x => x.UserName.Contains(input.Keyword) || x.Name.Contains(input.Keyword) || x.EmailAddress.Contains(input.Keyword))
                .WhereIf(input.IsActive.HasValue, x => x.IsActive == input.IsActive);
        }

        protected override async Task<User> GetEntityByIdAsync(long id)
        {
            var user = await Repository.GetAllIncluding(x => x.Roles).FirstOrDefaultAsync(x => x.Id == id);

            if (user == null)
            {
                throw new EntityNotFoundException(typeof(User), id);
            }

            return user;
        }

        protected override IQueryable<User> ApplySorting(IQueryable<User> query, PagedUserResultRequestDto input)
        {
            return query.OrderBy(r => r.UserName);
        }

        private void CheckErrors(IdentityResult identityResult)
        {
            identityResult.CheckErrors(LocalizationManager);
        }

        public async Task<bool> ChangePassword(ChangePasswordDto input)
        {
            if (_abpSession.UserId == null)
            {
                throw new UserFriendlyException("修改密码前请先登录.");
            }
            long userId = _abpSession.UserId.Value;
            var user = await _userManager.GetUserByIdAsync(userId);
            var loginAsync = await _logInManager.LoginAsync(user.UserName, input.CurrentPassword, shouldLockout: false);
            if (loginAsync.Result != AbpLoginResultType.Success)
            {
                throw new UserFriendlyException("密码错误");
            }
            if (!new Regex(AccountAppService.PasswordRegex).IsMatch(input.NewPassword))
            {
                throw new UserFriendlyException("密码需要为6-16位字符，。");
            }
            user.Password = _passwordHasher.HashPassword(user, input.NewPassword);
            CurrentUnitOfWork.SaveChanges();
            return true;
        }

        /// <summary>
        /// 分配角色
        /// </summary>
        /// <param name="userId">用户Id</param>
        /// <param name="roleName">角色名称(选中的全部)</param>
        /// <returns></returns>
        public async Task SetRoles([Required] long userId, [Required] List<string> roleName)
        {
            CheckUpdatePermission();
            var user = await _userManager.GetUserByIdAsync(userId);
            if (user.Name == AbpUserBase.AdminUserName
                && !roleName.Select(x => x.ToUpper()).Contains(StaticRoleNames.Tenants.Admin.ToUpper()))
                throw new UserFriendlyException("禁止移除系统管理员Admin权限");
            CheckErrors(await _userManager.SetRolesAsync(user, roleName.ToArray()));
        }

        /// <summary>
        /// 是否启用
        /// </summary>
        /// <param name="userId">用户Id</param>
        /// <param name="isActive">是否启用</param>
        /// <returns></returns>
        public async Task Activate([Required] long userId, bool isActive)
        {
            CheckUpdatePermission();
            var user = await _userManager.GetUserByIdAsync(userId);

            if (user.UserName == AbpUserBase.AdminUserName)
            {
                if (!isActive)
                    throw new UserFriendlyException("管理员账号不能被禁用");
            }
            user.IsActive = isActive;
            CheckErrors(await _userManager.UpdateAsync(user));
        }

        /// <summary>
        /// 删除用户
        /// </summary>
        /// <param name="userIdList"></param>
        /// <returns></returns>
        public async Task DeleteList([Required] List<long> userIdList)
        {
            foreach (var id in userIdList)
            {
                await DeleteAsync(new EntityDto<long>(id));
            }
        }

        public async Task<bool> ResetPassword(ResetPasswordDto input)
        {
            if (_abpSession.UserId == null)
            {
                throw new UserFriendlyException("重置密码前请先登录。");
            }
            long currentUserId = _abpSession.UserId.Value;
            var currentUser = await _userManager.GetUserByIdAsync(currentUserId);
            var loginAsync = await _logInManager.LoginAsync(currentUser.UserName, input.AdminPassword, shouldLockout: false);
            if (loginAsync.Result != AbpLoginResultType.Success)
            {
                throw new UserFriendlyException("您的“管理密码”与记录上的不匹配。请再试一次。");
            }
            if (currentUser.IsDeleted || !currentUser.IsActive)
            {
                return false;
            }
            var roles = await _userManager.GetRolesAsync(currentUser);
            if (!roles.Contains(StaticRoleNames.Tenants.Admin))
            {
                throw new UserFriendlyException("只有管理员可以重置密码。");
            }

            var user = await _userManager.GetUserByIdAsync(input.UserId);
            if (user != null)
            {
                user.Password = _passwordHasher.HashPassword(user, input.NewPassword);
                CurrentUnitOfWork.SaveChanges();
            }

            return true;
        }
    }
}

