using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using MTWorkHR.Application.Exceptions;
using MTWorkHR.Application.Filters;
using MTWorkHR.Application.Identity;
using MTWorkHR.Application.Mapper;
using MTWorkHR.Application.Models;
using MTWorkHR.Application.Services.Interfaces;
using MTWorkHR.Core.Global;
using MTWorkHR.Infrastructure.Entities;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace MTWorkHR.Identity.Services
{
    public class AuthService : IAuthService
    {
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly SignInManager<ApplicationUser> _signInManager;
        private readonly AppSettingsConfiguration _configuration;
        private readonly IUserService _userService;

        public AuthService(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager, AppSettingsConfiguration configuration, IUserService userService) 
        {
            _userManager = userManager;
            _signInManager = signInManager;
            _configuration = configuration;
            _userService = userService;
        }
        public async Task<AuthResponse> Login(AuthRequest request)
        {
            var user = await _userManager.FindByEmailAsync(request.Email);           
            if (user == null)
            {
                throw new AppException(ExceptionEnum.EmailNotExist);
            }
            var roles = await _userManager.GetRolesAsync(user);
            if (roles.Any(r => r == "Admin"))
            {
                throw new AppException(ExceptionEnum.NotAuthorized);
            }
            if (user.IsStopped == true)
            {
                throw new AppException(ExceptionEnum.AccountLocked);
            }
            if (user.IsDeleted == true)
            {
                throw new AppException(ExceptionEnum.UserNotExist);
            }
            var result = await _signInManager.CheckPasswordSignInAsync(user, request.Password, false);
            if(!result.Succeeded)
            {
                throw new AppException(ExceptionEnum.WrongCredentials);
            }
            var userResponse = await _userService.GetById(user.Id);

            JwtSecurityToken jwtToken = await GenerateToken(user);

            var response = new AuthResponse
            {
                User = userResponse,
                //Id = user.Id,
                //Email = user.Email,
                //UserName = user.UserName,
                //UserTypeId = user.UserType,
                Token = new JwtSecurityTokenHandler().WriteToken( jwtToken),
                Expiration = jwtToken.ValidTo
            };
            return response;
        }
      

        private async Task<JwtSecurityToken> GenerateToken(ApplicationUser user)
        {
            var userCalims = await _userManager.GetClaimsAsync(user);
            var roles = await _userManager.GetRolesAsync(user);
            var roleClaims = roles.Select(r => new Claim(ClaimTypes.Role, r)).ToList();
            var claims = new[]
            {
                new Claim(JwtRegisteredClaimNames.Name, user.UserName),
                new Claim(JwtRegisteredClaimNames.Email, user.Email),
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                new Claim("companyId", user.CompanyId+""),
                new Claim("uid", user.Id)
            }.Union(userCalims)
            .Union(roleClaims);
            var symmetricSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration.JwtSettings.SecretKey));
            var signingCredentials = new SigningCredentials(symmetricSecurityKey, SecurityAlgorithms.HmacSha256);
            var jwtSecurityToken = new JwtSecurityToken(
                issuer: _configuration.JwtSettings.Issuer,
                audience: _configuration.JwtSettings.Audience,
                claims: claims,
                expires: DateTime.UtcNow.AddMinutes(_configuration.JwtSettings.DurationInMinutes),
                signingCredentials: signingCredentials
                );
            return jwtSecurityToken;
        }

        public async Task<AuthResponse> AdminLogin(AuthRequest request)
        {
            var user = await _userManager.FindByEmailAsync(request.Email);
            if (user == null)
            {
                throw new AppException(ExceptionEnum.EmailNotExist);
            }
            var roles = await _userManager.GetRolesAsync(user);
            if(!roles.Any(r => r == "Admin"))
            {
                throw new AppException(ExceptionEnum.NotAuthorized);
            }
            var roleClaims = roles.Select(r => new Claim(ClaimTypes.Role, r)).ToList();

            var result = await _signInManager.CheckPasswordSignInAsync(user, request.Password, false);
            if (!result.Succeeded)
            {
                throw new AppException(ExceptionEnum.WrongCredentials);
            }
            var userResponse = await _userService.GetById(user.Id);

            JwtSecurityToken jwtToken = await GenerateToken(user);

            var response = new AuthResponse
            {
                User = userResponse,
                Token = new JwtSecurityTokenHandler().WriteToken(jwtToken),
                Expiration = jwtToken.ValidTo
            };
            return response;
        }
    }
  
}
