using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Reflection;
using System.Text;

namespace Knoks.Api.Filters
{
    public class LoggingActionFilter : Attribute, IActionFilter
    {
        private readonly ILogger _logger;

        public LoggingActionFilter(ILogger<LoggingActionFilter> logger)
        {
            _logger = logger;
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
        }

        private readonly static JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings { ContractResolver = new LoggingContractResolver() };
        public void OnActionExecuting(ActionExecutingContext context)
        {
            //var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
            var request = context.HttpContext.Request;
            var msg = new StringBuilder().AppendLine();
            msg.AppendLine($"On action executing: {request.Method} {request.GetDisplayUrl()}");
            msg.AppendLine($"Controller method: {context.ActionDescriptor.DisplayName}");
            if (context.ActionArguments.Count > 0)
            {
                msg.AppendLine("Arguments JSON:");
                msg.AppendLine(JsonConvert.SerializeObject(context.ActionArguments, Formatting.Indented, JsonSerializerSettings));
            }

            _logger.LogInformation(msg.ToString());
        }
    }

    public class LoggingContractResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            var property = base.CreateProperty(member, memberSerialization);
            property.Ignored = IsConfidential(member.Name);
            return property;
        }

        private readonly static string[] ConfidentialMembers = new string[] { "Password", "HttpRequestInfo", "Email" };
        private bool IsConfidential(string name)
        {
            foreach (var member in ConfidentialMembers)
                if (name.IndexOf(member, StringComparison.OrdinalIgnoreCase) != -1)
                    return true;

            return false;
        }
    }
}
