namespace Hims.Api.Services
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Claims;
    using System.Threading.Tasks;
    using Domain.Services;
    using IdentityModel;
    using IdentityServer4.Models;
    using IdentityServer4.Services;
    using Shared.EntityModels;

    /// <inheritdoc />
    /// <summary>
    /// The profile service.
    /// </summary>
    public class ProfileServices : IProfileService
    {
        /// <summary>
        /// The account services.
        /// </summary>
        private readonly IAccountService accountServices;

        /// <inheritdoc cref="accountServices" />
        public ProfileServices(IAccountService accountServices) => this.accountServices = accountServices;

        /// <inheritdoc />
        public async Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            var accountId = GetAccountId(context.Subject.Claims);
            if (accountId > 0)
            {
                var role = await this.accountServices.GetRoleAsync(accountId);
                var claims = FetchClaims(role);
                context.IssuedClaims.AddRange(claims);
            }
        }

        /// <inheritdoc />
        public async Task IsActiveAsync(IsActiveContext context)
        {
            var accountId = GetAccountId(context.Subject.Claims);
            context.IsActive = await Task.Run(() => accountId > 0);
        }

        /// <summary>
        /// The get role id.
        /// </summary>
        /// <param name="claims">
        /// The claims.
        /// </param>
        /// <returns>
        /// The <see cref="int"/>.
        /// </returns>
        private static int GetAccountId(IEnumerable<Claim> claims)
        {
            var accountIdClaim = claims.FirstOrDefault(x => x.Type == "sub");
            if (accountIdClaim == null || string.IsNullOrEmpty(accountIdClaim.Value))
            {
                return 0;
            }

            return !string.IsNullOrEmpty(accountIdClaim.Value) && int.Parse(accountIdClaim.Value) > 0
                       ? Convert.ToInt32(accountIdClaim.Value)
                       : 0;
        }

        /// <summary>
        /// The get user claims.
        /// </summary>
        /// <param name="role">
        /// The role model.
        /// </param>
        /// <returns>
        /// The claims.
        /// </returns>
        private static IEnumerable<Claim> FetchClaims(RoleModel role) =>
            new List<Claim>
                {
                    new Claim("roleId", role.RoleId.ToString(), ClaimValueTypes.Integer),
                    new Claim(JwtClaimTypes.Role, role.RoleName)
                };
    }
}
