using Diligent.WebAPI.Business.Interfaces;
using Diligent.WebAPI.Data.Entities;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace Diligent.WebAPI.Business.Services
{
    public class AuthenticationService:IAuthenticationService
    {
        private readonly UserManager<Customer> _customerManager;
        private readonly IConfiguration _configuration;
        private Customer customer;
        public AuthenticationService(UserManager<Customer> customerManager,IConfiguration configuration)
        {
            _customerManager = customerManager;
            _configuration = configuration;
        }

        public async Task<bool> ValidateCustomer(string username,string password)
        {
            customer = await _customerManager.FindByNameAsync(username);
            return (customer != null && await _customerManager.CheckPasswordAsync
            (customer, password));
        }

        public async Task<string> GenerateToken()
        {
            var signingCredentials = GetSigningCredentials();
            var claims = await GetClaims();
            var tokenOptions = GenerateTokenOptions(signingCredentials, claims);
            // return created token as string
            return new JwtSecurityTokenHandler().WriteToken(tokenOptions);
        }

        private async Task<List<Claim>> GetClaims()
        {
            //method creates a list of claims with the user name inside and all the roles the user belongs to.
            Claim claim = new (ClaimTypes.Name, customer.UserName);

            var claims = new List<Claim>
            {
                claim
            };

            IList<string> roles = await _customerManager.GetRolesAsync(customer);

            foreach (var role in roles)
            {
                claims.Add(new Claim(ClaimTypes.Role, role));
            }

            return claims;
        }

        private SigningCredentials GetSigningCredentials()
        {
            // This method returns secret key as a byte array with the security algorithm
            var jwtSettings = _configuration.GetSection("JwtSettings");
            var key = Encoding.UTF8.GetBytes(jwtSettings["jwtSecret"]);
            var secret = new SymmetricSecurityKey(key);
            return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256);
        }

        private JwtSecurityToken GenerateTokenOptions(SigningCredentials
            signingCredentials, List<Claim> claims)
        {
            //return an object of the JwtSecurityToken type with all of the required options
            var jwtSettings = _configuration.GetSection("JwtSettings");
            var tokenOptions = new JwtSecurityToken
            (
                issuer: jwtSettings.GetSection("validIssuer").Value,
                audience: jwtSettings.GetSection("validAudience").Value,
                claims: claims,
                expires: DateTime.Now.AddDays(7),
                signingCredentials: signingCredentials
            );
            return tokenOptions;
        }
    }
}
