using System.Security.Authentication;
using System.Security.Claims;
using IdentityModel;
using Microsoft.AspNetCore.Http;
using XF.Domain.Dependency;
using XF.Domain.Extensions;

namespace XF.Domain.Authentications
{
    public class DefaultSessionContext : ISessionContext, IScopeDependency
    {
        public DefaultSessionContext(IHttpContextAccessor httpContextAccessor)
        {
            var httpContext = httpContextAccessor.HttpContext;
            if (httpContext is null)
                //throw new ArgumentNullException(nameof(httpContext));
                return;

            var user = httpContext.User;
            //UserId = user.FindFirstValue(JwtClaimTypes.Id);
            UserId = user.FindFirstValue(ClaimTypes.NameIdentifier);
            UserName = user.FindFirstValue(AppClaimTypes.UserDisplayName);
            Phone = user.FindFirstValue(JwtClaimTypes.PhoneNumber);
            //Roles = user.Claims.Where(d => d.Type == JwtClaimTypes.Role).Select(d => d.Value).ToArray();
            Roles = user.Claims.Where(d => d.Type == ClaimTypes.Role).Select(d => d.Value).ToArray();
            OrgId = user.FindFirstValue(AppClaimTypes.DepartmentId);
            //OrgCode = user.FindFirstValue(AppClaimTypes.DepartmentCode);
            OrgName = user.FindFirstValue(AppClaimTypes.DepartmentName);
            OrgLevel = user.FindIntValue(AppClaimTypes.DepartmentLevel);
            OrgAreaCode = user.FindFirstValue(AppClaimTypes.DepartmentAreaCode);
            OrgAreaName = user.FindFirstValue(AppClaimTypes.DepartmentAreaName);
            OrgIsCenter = user.FindBoolValue(AppClaimTypes.DepartmentIsCenter);
            AreaId = user.FindFirstValue(AppClaimTypes.AreaId);
            ClientId = user.FindFirstValue(JwtClaimTypes.ClientId);
            StaffNo = user.FindFirstValue(AppClaimTypes.StaffNo);
        }

        /// <summary>
        /// Id of current tenant or null for host
        /// </summary>
        public string? UserId { get; }

        /// <summary>
        /// Id of current user or throw Exception for guest
        /// </summary>
        /// <exception cref="AuthenticationException"></exception>
        public string RequiredUserId => UserId ?? throw new ArgumentNullException();

        public string? UserName { get; }

        public string? Phone { get; }

        /// <summary>
        /// Roles
        /// </summary>
        public string[] Roles { get; }

        public string? OrgId { get; set; }
        public string? OrgCode { get; set; }
        public string? OrgName { get; set; }

        public int OrgLevel { get; set; }
        public string? OrgAreaCode { get; set; }
        public bool OrgIsCenter { get; set; }

        /// <summary>
        /// 部门行政区划名称
        /// </summary>
        public string? OrgAreaName { get; set; }

        public string? AreaId { get; set; }

        public string RequiredOrgId => OrgId ?? throw new ArgumentNullException();
        
        public string? ClientId { get; }

        /// <summary>
        /// 工号
        /// </summary>
        public string? StaffNo { get; }
    }

    public static class ClaimsPrincipalExtensions
    {
        public static int FindIntValue(this ClaimsPrincipal claims, string claimType)
        {
            var value = claims.FindFirstValue(claimType);
            return int.TryParse(value, out int result) ? result : default;
        }

        public static bool FindBoolValue(this ClaimsPrincipal claims, string claimType)
        {
            var value = claims.FindFirstValue(claimType);
            return bool.TryParse(value, out bool result) ? result : default;
        }
    }
}