using System;
using System.Linq;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using SharpRSS.API.Contracts.Models;
using SharpRSS.API.Data;
using SharpRSS.API.Models;
using ToolQit;
using ToolQit.Extensions;
using ToolQit.Logging;

namespace SharpRSS.API.Auth
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
    public class SessionAuthorizeAttribute : Attribute, IAuthorizationFilter
    {
        public SessionAuthorizeAttribute(bool admin = true)
        {
            _admin = admin;
            _log = LogManager.CreateLogger(typeof(SessionAuthorizeAttribute));
        }
        
        private readonly ILog _log;
        private readonly bool _admin;
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            if (context.ActionDescriptor.EndpointMetadata.Any(obj => obj.GetType() == typeof(AllowAnonymousAttribute)))
                return;
            var authService = context.HttpContext.RequestServices.GetService(typeof(AuthService)) as AuthService;
            if (authService == null)
            {
                context.Result = new UnauthorizedObjectResult(new Result("Failed to initialize service!", ResultStatus.InternalFail));
                return;
            }

            if (context.HttpContext.Request.Headers.TryGetValue("SRSS-Session", out var val))
            {
                string? headerVal = val.ToString();
                if (headerVal == null || headerVal.IsNullEmptyWhiteSpace())
                {
                    context.Result = new UnauthorizedObjectResult(new Result("Invalid session ID"));
                    return;
                }
                var authSetResult = authService.ValidateSession(headerVal).Result;
                if (!authSetResult.Success || authSetResult.Value == null)
                {
                    context.Result = new UnauthorizedResult();
                    return;
                }
                if (authSetResult.Value.Session is { Expired: true })
                {
                    context.Result = new UnauthorizedObjectResult(new Result("Session expired", ResultStatus.Failed));
                    return;
                }
                if (!authSetResult.Value.User.Active)
                {
                    context.Result = new UnauthorizedObjectResult(new Result(
                        "User is not active, contact your administrator to enable this account!", ResultStatus.Failed));
                    return;
                }

                authSetResult.Value.AdminRequired = _admin;
                context.RouteData.Values.Add(nameof(AuthorizationSet), authSetResult.Value);
                return;
            }
            context.Result = new UnauthorizedResult();
        }
    }
}