using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;

namespace AsbCloudWebApi.Middlewares
{

    public class PermissionsMiddlware
    {
        private readonly RequestDelegate next;
        private readonly UserConnectionsLimitMiddlware userConnectionsLimitMiddlware;

        public PermissionsMiddlware(RequestDelegate next, IConfiguration configuration)
        {
            this.next = next;
            userConnectionsLimitMiddlware = new UserConnectionsLimitMiddlware(next, configuration);
        }

        public async Task InvokeAsync(HttpContext context)
        {
            var endpoint = context.GetEndpoint();
            var permission = endpoint?.Metadata.GetMetadata<PermissionAttribute>();
            if (permission is null)
            {
                await next(context);
                return;
            }

            var idUser = context.User.GetUserId();
            if (idUser is null)
            {
                await context.ForbidAsync();
                return;
            }

            var controllerName = endpoint!.Metadata
                .GetMetadata<Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor>()
                ?.ControllerName;

            bool isAuthorized;
            if (idUser == 1)
                isAuthorized = true;
            else
            {
                var permissionName = permission.Name;
                if (string.IsNullOrEmpty(permissionName))
                {
                    var httpMethod = endpoint.Metadata
                        .GetMetadata<Microsoft.AspNetCore.Routing.HttpMethodMetadata>()
                        ?.HttpMethods[0]
                        .ToLower();

                    permissionName = httpMethod switch
                    {
                        "get" or "delete" => $"{controllerName}.{httpMethod}",
                        "post" or "put" or "patch" => $"{controllerName}.edit",
                        _ => throw new NotImplementedException(),
                    };
                    PermissionAttribute.Registered.Add(permissionName);
                }
                else if (permissionName.Contains("[controller]"))
                {
                    permissionName = permissionName.Replace("[controller]", controllerName);
                    PermissionAttribute.Registered.Add(permissionName);
                }

                var userService = context.RequestServices.GetRequiredService<IUserRepository>();
                isAuthorized = userService.HasPermission(idUser.Value, permissionName);
            }

            if (isAuthorized)
                await userConnectionsLimitMiddlware.InvokeAsync(context, idUser!.Value, controllerName!);
            else
                await context.ForbidAsync();
        }
    }

}