using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace Hotline.Api.Filter
{
    public class ClientIpFilterAttribute : ActionFilterAttribute
    {
        private readonly List<string> _whiteIps;
        private readonly ILogger _logger;

        public ClientIpFilterAttribute(List<string> whiteIps, ILogger logger)
        {
            _whiteIps = whiteIps;
            _logger = logger;
        }

        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (!_whiteIps.Any()) return;

            var ip = context.HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrEmpty(ip))
                ip = context.HttpContext.Request.Headers["X-Real-IP"].FirstOrDefault();

            if (string.IsNullOrEmpty(ip))
            {
                var remoteIp = context.HttpContext.Connection.RemoteIpAddress;
                if (remoteIp?.IsIPv4MappedToIPv6 ?? false)
                    remoteIp = remoteIp.MapToIPv4();
                ip = remoteIp?.ToString();
            }

            _logger.LogWarning("Request from IP: {RemoteIp}", ip);

            if (ip.StartsWith(':') || ip.StartsWith("::"))
                ip = ip.Replace(':', ' ').Trim();

            if (string.IsNullOrEmpty(ip))
            {
                _logger.LogWarning("Forbidden Request from IP: {RemoteIp}", ip);
                context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
            }

            if (!_whiteIps.Contains(ip))
            {
                _logger.LogWarning("Forbidden Request from IP: {RemoteIp}", ip);
                context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
            }

            base.OnActionExecuting(context);
        }
    }
}
