using System;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http.Filters;
using Kreta.Core.Enum;
using Kreta.Core.Exceptions;
using Kreta.Core.Validation.Exceptions;
using Kreta.Core.Validation.Exceptions.Enum;
using Kreta.Core.Validation.Extensions;
using Kreta.Framework;
using Kreta.Framework.Entities;
using Kreta.Resources;
using Kreta.Web.Helpers.Error;
using Kreta.Web.Logging.Extensions;
using Kreta.Web.Logging.Logger;

namespace Kreta.Web.App_Start
{
    public class ApiCustomExceptionAttribute : ExceptionFilterAttribute
    {
        public override void OnException(HttpActionExecutedContext context)
        {
            Guid? logId;
            if (Areas.MobileApi.ModelConverter.MobileUserModelConverter.TryLoadFromHttpContext(out _))
            {
                HandleMobilExeptionFormat(context, out logId);
            }
            else
            {
                HandleWebExeptionFormat(context, out logId);
            }

            if (logId.HasValue)
            {
                if (!context.Exception.Data.Contains(RequestResponseLoggingFields.Server.ExceptionId))
                {
                    context.Exception.Data.Add(RequestResponseLoggingFields.Server.ExceptionId, logId);
                }

                HttpContext.Current.AddException(context.Exception);
            }
        }

        private bool HandleMobilExeptionFormat(HttpActionExecutedContext context, out Guid? logId)
        {
            logId = null;
            if (context.Exception is ValidationException vException)
            {
                context.Response = context.Request.CreateResponse(vException.GetHttpStatusCode(), vException);
                return false;
            }
            if (context.Exception is BlException blException)
            {
                var validationErrorType = GetValidationErrorTypeByBlExceptionType(blException.ExceptionType);

                var validationException = new ValidationException(validationErrorType, blException.Message);
                context.Response = context.Request.CreateResponse(validationException.GetHttpStatusCode(), validationException);

                return false;
            }
            if (context.Exception is StatusError statusError)
            {
                bool logException = false;
                if (statusError.UnHandledException != null)
                {
                    logId = LogInDb(statusError.UnHandledException, context.Request.Headers.Host);
                    logException = true;
                }

                if (statusError.StatusCode != (int)HttpStatusCode.InternalServerError || !logException)
                {
                    var validationException = new ValidationException(ValidationErrorType.Undefined, statusError.Message);/*TODO:statuskód átadása jelenleg nincs rá ehetőség*/
                    context.Response = context.Request.CreateResponse(validationException.GetHttpStatusCode(), validationException);
                }
                else
                {
                    var generalExeption = new Exception(StringResourcesUtil.GetString(45));
                    context.Response = context.Request.CreateResponse(HttpStatusCode.InternalServerError, generalExeption);
                }

                return logException;
            }

            if (context.Exception is EntityNotFoundException)
            {
                logId = LogInDb(context.Exception, context.Request.Headers.Host);
                var validationException = new ValidationException(ValidationErrorType.ResourceNotFound, ErrorResource.AzElemNemTalalhato);
                context.Response = context.Request.CreateResponse(validationException.GetHttpStatusCode(), validationException);
                return true;
            }

            logId = LogInDb(context.Exception, context.Request.Headers.Host);
            var exception = new Exception(StringResourcesUtil.GetString(45));
            context.Response = context.Request.CreateResponse(HttpStatusCode.InternalServerError, exception);
            return true;
        }

        private ValidationErrorType GetValidationErrorTypeByBlExceptionType(BlExceptionType exceptionType)
        {
            if (exceptionType == BlExceptionType.IntezmenyMarTanevetValtott)
            {
                return ValidationErrorType.IntezmenyMarTanevetValtott;
            }

            return ValidationErrorType.Undefined;
        }

        private bool HandleWebExeptionFormat(HttpActionExecutedContext context, out Guid? logId)
        {
            logId = null;

            if (context.Exception is StatusError)
            {
                var ex = context.Exception as StatusError;
                bool logException = false;
                if (ex.UnHandledException != null)
                {
                    logId = LogInDb(ex.UnHandledException, context.Request.Headers.Host);
                    logException = true;
                }

                context.Response = context.Request.CreateResponse((HttpStatusCode)ex.StatusCode, new ErrorModel
                {
                    Message = ex.Message,
                    Json = ex.Json,
                    Status = ex.StatusCode,
                    IsMvc = false,
                    ErrorCode = logId,
                    CloseFunction = ex.CloseFunction
                });

                return logException;
            }

            if (context.Exception is ValidationException)
            {
                var ex = context.Exception as ValidationException;
                var text = string.Empty;
                foreach (var error in ex.ValidationItems)
                {
                    text = text + Environment.NewLine + error.Message;
                }
                if (string.IsNullOrWhiteSpace(text))
                {
                    text = ex.Message;
                }

                context.Response = context.Request.CreateResponse(HttpStatusCode.BadRequest, new ErrorModel
                {
                    Message = text,
                    Status = (int)HttpStatusCode.BadRequest,
                    IsMvc = false,
                    ErrorCode = logId
                });
                return false;
            }

            logId = LogInDb(context.Exception, context.Request.Headers.Host);
            context.Response = context.Request.CreateResponse(HttpStatusCode.InternalServerError, new ErrorModel
            {
                Message = StringResourcesUtil.GetString(45)/*Hiba történt az oldalon*/,
                Status = (int)HttpStatusCode.InternalServerError,
                IsMvc = false,
                ErrorCode = logId
            });

            return true;
        }

        private Guid? LogInDb(Exception ex, string host)
        {
            return SDAServer.Instance.Logger.ExceptionThrown(ex, host);
        }
    }
}