using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Net;
namespace BankSampahApp.Filters;
/// 
/// Global exception filter untuk menangani error secara terpusat
/// 
public class GlobalExceptionFilter : IExceptionFilter
{
    private readonly ILogger _logger;
    private readonly IWebHostEnvironment _environment;
    /// 
    /// Constructor dengan dependency injection
    /// 
    /// Logger untuk logging
    /// Environment information
    public GlobalExceptionFilter(
        ILogger logger,
        IWebHostEnvironment environment)
    {
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        _environment = environment ?? throw new ArgumentNullException(nameof(environment));
    }
    /// 
    /// Handle exception yang terjadi di aplikasi
    /// 
    /// Exception context
    public void OnException(ExceptionContext context)
    {
        var exception = context.Exception;
        var requestId = context.HttpContext.TraceIdentifier;
        // Log the exception with details
        _logger.LogError(exception,
            "Unhandled exception occurred. RequestId: {RequestId}, Path: {Path}, Method: {Method}, User: {User}",
            requestId,
            context.HttpContext.Request.Path,
            context.HttpContext.Request.Method,
            context.HttpContext.User?.Identity?.Name ?? "Anonymous");
        // Determine response based on request type
        if (IsApiRequest(context.HttpContext.Request))
        {
            HandleApiException(context, exception, requestId);
        }
        else
        {
            HandleWebException(context, exception, requestId);
        }
    }
    /// 
    /// Handle exception untuk API requests
    /// 
    /// Exception context
    /// Exception yang terjadi
    /// Request ID
    private void HandleApiException(ExceptionContext context, Exception exception, string requestId)
    {
        var statusCode = GetStatusCodeFromException(exception);
        var includeDetails = _environment.IsDevelopment();
        var response = new
        {
            Error = new
            {
                Message = includeDetails ? exception.Message : "An error occurred while processing your request.",
                RequestId = requestId,
                Details = includeDetails ? exception.ToString() : null,
                Type = exception.GetType().Name,
                Timestamp = DateTime.UtcNow
            }
        };
        context.Result = new JsonResult(response)
        {
            StatusCode = (int)statusCode
        };
        context.ExceptionHandled = true;
    }
    /// 
    /// Handle exception untuk Web requests
    /// 
    /// Exception context
    /// Exception yang terjadi
    /// Request ID
    private void HandleWebException(ExceptionContext context, Exception exception, string requestId)
    {
        var statusCode = GetStatusCodeFromException(exception);
        // Set status code
        context.HttpContext.Response.StatusCode = (int)statusCode;
        // Store exception details untuk error page
        context.HttpContext.Items["Exception"] = exception;
        context.HttpContext.Items["RequestId"] = requestId;
        // Redirect to error page
        var routeData = new RouteData();
        routeData.Values["controller"] = "Home";
        routeData.Values["action"] = "Error";
        context.Result = new RedirectToRouteResult(routeData);
        context.ExceptionHandled = true;
    }
    /// 
    /// Determine HTTP status code based on exception type
    /// 
    /// Exception
    /// HTTP status code
    private static HttpStatusCode GetStatusCodeFromException(Exception exception)
    {
        return exception switch
        {
            ArgumentNullException => HttpStatusCode.BadRequest,
            ArgumentException => HttpStatusCode.BadRequest,
            UnauthorizedAccessException => HttpStatusCode.Unauthorized,
            NotImplementedException => HttpStatusCode.NotImplemented,
            TimeoutException => HttpStatusCode.RequestTimeout,
            _ => HttpStatusCode.InternalServerError
        };
    }
    /// 
    /// Check if request is API request
    /// 
    /// HTTP request
    /// True if API request
    private static bool IsApiRequest(HttpRequest request)
    {
        // Check if request accepts JSON or has API path
        return request.Headers["Accept"].ToString().Contains("application/json") ||
               request.Path.StartsWithSegments("/api") ||
               request.Path.StartsWithSegments("/health");
    }
}