/*
* Copyright (c) Akveo 2019. All Rights Reserved.
* Licensed under the Personal / Commercial License.
* See LICENSE_PERSONAL / LICENSE_COMMERCIAL in the project root for license information on type of purchased license.
*/

using Common.DTO;
using Common.IdentityManagement;
using Microsoft.AspNet.Identity;
using System.Threading.Tasks;
using System.Web;

namespace Common.WebApi.Identity
{
    public class AuthenticationService<TUser> : IAuthenticationService
        where TUser : Entities.User, IUser<int>, new()
    {
        protected readonly UserManager<TUser, int> userManager;
        public AuthenticationService(UserManager<TUser, int> userManager)
        {
            this.userManager = userManager;
        }

        public async Task<AuthResult> Login(LoginDTO loginDto)
        {
            if (loginDto == null || string.IsNullOrEmpty(loginDto.Email) || string.IsNullOrEmpty(loginDto.Password))
                return AuthResult.UnvalidatedResult;

            var user = await userManager.FindByEmailAsync(loginDto.Email);

            if (user != null && user.Id > 0)
            {
                if (await userManager.CheckPasswordAsync(user, loginDto.Password))
                {
                    var token = JwtManager.GenerateToken(await userManager.CreateIdentityAsync(user));
                    return AuthResult.TokenResult(token);
                }
            }

            return AuthResult.UnauthorizedResult;
        }

        public async Task<AuthResult> ChangePassword(ChangePasswordDTO changePasswordDto)
        {
            if (changePasswordDto == null ||
                string.IsNullOrEmpty(changePasswordDto.ConfirmPassword) ||
                string.IsNullOrEmpty(changePasswordDto.Password) ||
                changePasswordDto.Password != changePasswordDto.ConfirmPassword
            )
                return AuthResult.UnvalidatedResult;

            int.TryParse(HttpContext.Current.User.Identity.GetUserId(), out var currentUserId);
            if (currentUserId > 0)
            {
                var result = await userManager.ChangePasswordAsync(currentUserId, null, changePasswordDto.Password);
                if (result.Succeeded)
                    return AuthResult.SucceededResult;
            }

            return AuthResult.UnauthorizedResult;
        }

        public async Task<AuthResult> SignUp(SignUpDTO signUpDto)
        {
            if (signUpDto == null ||
                string.IsNullOrEmpty(signUpDto.Email) ||
                string.IsNullOrEmpty(signUpDto.Password) ||
                string.IsNullOrEmpty(signUpDto.ConfirmPassword) ||
                string.IsNullOrEmpty(signUpDto.FullName) ||
                signUpDto.Password != signUpDto.ConfirmPassword
            )
                return AuthResult.UnvalidatedResult;

            var newUser = new TUser { UserName = signUpDto.FullName, Email = signUpDto.Email };

            var result = await userManager.CreateAsync(newUser, signUpDto.Password);

            if (result.Succeeded)
            {
                if (newUser.Id > 0)
                {
                    await userManager.AddToRoleAsync(newUser.Id, "User");
                    var token = JwtManager.GenerateToken(await userManager.CreateIdentityAsync(newUser));
                    return AuthResult.TokenResult(token);
                }
            }

            return AuthResult.UnauthorizedResult;
        }

        public async Task<AuthResult> RequestPassword(RequestPasswordDTO requestPasswordDto)
        {
            if (requestPasswordDto == null ||
                string.IsNullOrEmpty(requestPasswordDto.Email))
                return AuthResult.UnvalidatedResult;

            var user = await userManager.FindByEmailAsync(requestPasswordDto.Email);

            if (user != null && user.Id > 0)
            {
                var passwordResetToken = await userManager.GeneratePasswordResetTokenAsync(user.Id);
                return AuthResult.TokenResult(passwordResetToken);
            }

            return AuthResult.UnvalidatedResult;
        }

        public async Task<AuthResult> RestorePassword(RestorePasswordDTO restorePasswordDto)
        {
            if (restorePasswordDto == null ||
                string.IsNullOrEmpty(restorePasswordDto.Email) ||
                string.IsNullOrEmpty(restorePasswordDto.Token) ||
                string.IsNullOrEmpty(restorePasswordDto.NewPassword) ||
                string.IsNullOrEmpty(restorePasswordDto.ConfirmPassword) ||
                string.IsNullOrEmpty(restorePasswordDto.ConfirmPassword) ||
                restorePasswordDto.ConfirmPassword != restorePasswordDto.NewPassword
            )
                return AuthResult.UnvalidatedResult;

            var user = await userManager.FindByEmailAsync(restorePasswordDto.Email);

            if (user != null && user.Id > 0)
            {
                var result = await userManager.ResetPasswordAsync(user.Id, restorePasswordDto.Token, restorePasswordDto.NewPassword);

                if (result.Succeeded)
                {
                    var token = JwtManager.GenerateToken(await userManager.CreateIdentityAsync(user));
                    return AuthResult.TokenResult(token);
                }
            }

            return AuthResult.UnvalidatedResult;
        }

        public Task<AuthResult> SignOut()
        {
            throw new System.NotImplementedException();
        }
    }
}