using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;
using Haoliang.Core.Services;
using Haoliang.Models.Common;

namespace Haoliang.Api.Filters
{
    public class GlobalExceptionFilter : IExceptionFilter
    {
        private readonly ILogger<GlobalExceptionFilter> _logger;
        private readonly ILoggingService _loggingService;

        public GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger, ILoggingService loggingService)
        {
            _logger = logger;
            _loggingService = loggingService;
        }

        public void OnException(ExceptionContext context)
        {
            // Log the exception
            _logger.LogError(context.Exception, "An unhandled exception occurred");
            await _loggingService.LogErrorAsync($"Unhandled exception: {context.Exception.Message}", context.Exception);

            // Handle specific exception types
            if (context.Exception is ValidationException)
            {
                context.Result = CreateValidationResult(context.Exception as ValidationException);
                context.ExceptionHandled = true;
                return;
            }

            if (context.Exception is NotFoundException)
            {
                context.Result = new NotFoundObjectResult(CreateErrorResponse("Resource not found", 404));
                context.ExceptionHandled = true;
                return;
            }

            if (context.Exception is ForbiddenException)
            {
                context.Result = new ObjectResult(CreateErrorResponse("Access forbidden", 403))
                {
                    StatusCode = 403
                };
                context.ExceptionHandled = true;
                return;
            }

            if (context.Exception is BadRequestException)
            {
                context.Result = new BadRequestObjectResult(CreateErrorResponse("Bad request", 400));
                context.ExceptionHandled = true;
                return;
            }

            // Handle model state validation errors
            if (!context.ModelState.IsValid)
            {
                context.Result = new BadRequestObjectResult(CreateValidationErrorResponse(context.ModelState));
                context.ExceptionHandled = true;
                return;
            }

            // Default handling for unhandled exceptions
            context.Result = new ObjectResult(CreateErrorResponse("An unexpected error occurred", 500))
            {
                StatusCode = 500
            };
            context.ExceptionHandled = true;
        }

        private IActionResult CreateValidationResult(ValidationException validationException)
        {
            var response = new ApiResponse<Dictionary<string, string[]>>
            {
                Success = false,
                Message = "Validation failed",
                ErrorCode = 400,
                Data = validationException?.Errors as Dictionary<string, string[]> ?? new Dictionary<string, string[]>(),
                Timestamp = DateTime.Now
            };

            return new BadRequestObjectResult(response);
        }

        private object CreateErrorResponse(string message, int errorCode)
        {
            return new ApiResponse<object>
            {
                Success = false,
                Message = message,
                ErrorCode = errorCode,
                Timestamp = DateTime.Now
            };
        }

        private object CreateValidationErrorResponse(ModelStateDictionary modelState)
        {
            var errors = new Dictionary<string, string[]>();

            foreach (var keyModelStatePair in modelState)
            {
                var key = keyModelStatePair.Key;
                var errorsArray = keyModelStatePair.Value.Errors.Select(error => error.ErrorMessage).ToArray();

                if (errorsArray.Length > 0)
                {
                    errors[key] = errorsArray;
                }
            }

            return new ApiResponse<Dictionary<string, string[]>>
            {
                Success = false,
                Message = "Validation failed",
                ErrorCode = 400,
                Data = errors,
                Timestamp = DateTime.Now
            };
        }
    }

    public class ModelStateValidationFilter : IActionFilter
    {
        private readonly ILogger<ModelStateValidationFilter> _logger;

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

        public void OnActionExecuting(ActionExecutingContext context)
        {
            if (!context.ModelState.IsValid)
            {
                var errors = new Dictionary<string, string[]>();

                foreach (var keyModelStatePair in context.ModelState)
                {
                    var key = keyModelStatePair.Key;
                    var errorsArray = keyModelStatePair.Value.Errors.Select(error => error.ErrorMessage).ToArray();

                    if (errorsArray.Length > 0)
                    {
                        errors[key] = errorsArray;
                    }
                }

                _logger.LogWarning($"Model validation failed: {JsonSerializer.Serialize(errors)}");

                context.Result = new BadRequestObjectResult(new ApiResponse<Dictionary<string, string[]>>
                {
                    Success = false,
                    Message = "Validation failed",
                    ErrorCode = 400,
                    Data = errors,
                    Timestamp = DateTime.Now
                });
            }
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            // No operation needed
        }
    }
}