using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Http;
using System;
using System.Net;
using System.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Microsoft.Extensions.Logging;
using App.Metrics;
using AyaNova.Util;
using AyaNova.Biz;

namespace AyaNova.Api.ControllerHelpers
{


    /// <summary>
    /// This is essentially an unhandled exception handler
    /// </summary>
    public class ApiCustomExceptionFilter : IExceptionFilter
    {
        private readonly ILogger log;

        // public ApiCustomExceptionFilter(ILoggerFactory logger)
        // {
        //     if (logger == null)
        //     {
        //         throw new ArgumentNullException(nameof(logger));
        //     }

        //     this.log = logger.CreateLogger("Server Exception");
        // }

        public ApiCustomExceptionFilter(ILogger logger)
        {
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }

            this.log = logger;
        }


        public void OnException(ExceptionContext context)
        {
            HttpStatusCode status = HttpStatusCode.InternalServerError;
            String message = String.Empty;
            #region If need to refine this further and deal with specific types
            // var exceptionType = context.Exception.GetType();
            // if (exceptionType == typeof(UnauthorizedAccessException))
            // {
            //     message = "Unauthorized Access";
            //     status = HttpStatusCode.Unauthorized;
            // }
            // else if (exceptionType == typeof(NotImplementedException))
            // {
            //     message = "A server error occurred.";
            //     status = HttpStatusCode.NotImplemented;
            // }
            // // else if (exceptionType == typeof(MyAppException))
            // // {
            // //     message = context.Exception.ToString();
            // //     status = HttpStatusCode.InternalServerError;
            // // }
            // else
            // {
            #endregion
            message = context.Exception.Message;
            status = HttpStatusCode.InternalServerError;
            //}

            //No need to log test exceptions to check and filter out
            bool loggableError = true;

            if (message.StartsWith("Test exception"))
                loggableError = false;

            //LOG IT
            if (loggableError)
                log.LogError(context.Exception, "Error");


            //Track this exception
            IMetrics metrics = (IMetrics)ServiceProviderProvider.Provider.GetService(typeof(IMetrics));
            metrics.Measure.Meter.Mark(MetricsRegistry.UnhandledExceptionsMeter, context.Exception.GetType().ToString());


            HttpResponse response = context.HttpContext.Response;
            response.StatusCode = (int)status;
            response.ContentType = "application/json; charset=utf-8";

            //This line is critical, without it the response is not proper and fails in various clients (postman, xunit tests with httpclient)
            context.ExceptionHandled = true;
            //context.Result

            response.WriteAsync(JsonConvert.SerializeObject(
                new ApiErrorResponse(ApiErrorCode.API_SERVER_ERROR, "Server internal error", "See server log for details"),
                new JsonSerializerSettings
                {
                    ContractResolver = new CamelCasePropertyNamesContractResolver()
                }
                ));
        }


    }//eoc

}//eons