using LSFE.Domain.Services.Security;
using LSFE.Infrastructure.Database;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.EntityFrameworkCore;
using System.Security.Claims;

namespace LSFE.API.Security
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
    public class AuthorizeRolesAttribute : AuthorizeAttribute, IAsyncAuthorizationFilter
    {
        private readonly string _controllerName;

        public AuthorizeRolesAttribute(string controllerName)
        {
            _controllerName = controllerName;
        }

        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            try
            {
                var user = context.HttpContext.User;

                if (!user.Identity?.IsAuthenticated ?? true)
                {
                    context.Result = new JsonResult(new
                    {
                        Success = false,
                        MessCode = 0,
                        Message = "You must be logged in to access this resource."
                    })
                    {
                        StatusCode = StatusCodes.Status401Unauthorized
                    };
                    return;
                }

                var userId = user.FindFirstValue(ClaimTypes.NameIdentifier);

                if (string.IsNullOrEmpty(userId))
                {
                    context.Result = new UnauthorizedResult();
                    return;
                }

                var serviceProvider = context.HttpContext.RequestServices;

                var authCache = serviceProvider.GetService<IRoleAuthorizationCache>();

                bool hasAccess;

                if (authCache != null)
                {
                    // Use cached authorization check
                    hasAccess = await authCache.UserHasAccessAsync(userId, _controllerName);
                }
                else
                {
                    // Fallback to direct database query
                    var dbContext = serviceProvider.GetRequiredService<LSFEDbContext>();

                    hasAccess = await (
                        from ar in dbContext.AuthorizeRoles
                        join ur in dbContext.UserRoles on ar.RoleId equals ur.RoleId
                        where ar.IsActive
                            && ar.Controller == _controllerName
                            && ur.UserId == userId
                        select ar.AuthorizeRoleId
                    ).AnyAsync();
                }

                if (!hasAccess)
                {
                    context.Result = new JsonResult(new
                    {
                        Success = false,
                        MessCode = 0,
                        Message = "You don't have permission to access this page. Please contact your administrator."
                    })
                    {
                        StatusCode = StatusCodes.Status403Forbidden
                    };
                    return;
                }
            }
            catch (Exception ex)
            {
                context.Result = new JsonResult(new
                {
                    Success = false,
                    MessCode = 0,
                    Message = "An error occurred while checking permissions."
                })
                {
                    StatusCode = StatusCodes.Status500InternalServerError
                };
            }
        }
    }
}