using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;

namespace GreenTree.Strohrmann.ERP.Services.Authorization
{
    public class DefaultAuthorizationHandler : AuthorizationHandler<DefaultAuthorizationPolicy>
    {
        #region DI fields

        // The current authorization service
        private readonly IAuthorizationService _authorizationService;

        private readonly IHttpContextAccessor _httpContextAccessor;

        #endregion

        #region Properties

        /// <summary>
        /// The administration Options
        /// </summary>
        public AdministrationOptions Options { get; set; }

        #endregion

        #region DI Ctor

        /// <summary>
        /// Initializes a new instance of the DefaultAuthorizationHandler class
        /// </summary>
        /// <param name="authorizationService">The dependent authorization serivce.</param>
        /// <param name="administrationOptions">The global administration options.</param>
        public DefaultAuthorizationHandler(
            IAuthorizationService authorizationService,
            IConfiguration configuration,
            IHttpContextAccessor httpContextAccessor)
        {
            _authorizationService = authorizationService;

            var administrationOptions = configuration.GetSection("AdministrationOptions").Get<AdministrationOptions>();

            if (administrationOptions == null)
                throw new Exception("The appsettings.json does not contain administration options.");

            Options = administrationOptions;
            _httpContextAccessor = httpContextAccessor;
        }

        #endregion

        #region Implementation AuthorizationHandler

        /// <summary>
        /// Handle the current requirement for a specific resource
        /// </summary>
        /// <param name="context">The authorization context.</param>
        /// <param name="requirement">The requirement.</param>
        /// <returns>Returns a succeeded or failed task if the user is authorized for the required resource.</returns>
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, DefaultAuthorizationPolicy requirement)
        {
            // Check if the checked requirement is the default policy and allow access when authenticated
            if (requirement.Policy == String.Empty && context.User.Identity.IsAuthenticated)
            {
                context.Succeed(requirement);

                return Task.CompletedTask;
            }

            // Check admin state of user
            var isAdmin = context.User.Identity.Name == Options.Administrator;

            if (isAdmin)
            {
                context.Succeed(requirement);

                return Task.CompletedTask;
            }

            // Process the UserHasPolicy check from the current authorization service
            var isAuthorized = _authorizationService.UserHasPolicy(context.User.Identity, requirement.Policy);

            if (isAuthorized)
                context.Succeed(requirement);
            else
                context.Fail();

            return Task.CompletedTask;
        }

        #endregion
    }
}