<?php

namespace App\Exceptions;

use Illuminate\Auth\AuthenticationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\Exceptions\ThrottleRequestsException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Exceptions\InvalidSignatureException;
use Illuminate\Session\TokenMismatchException;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Throwable;

class Handler extends ExceptionHandler
{
    /**
     * The list of the inputs that are never flashed to the session on validation exceptions.
     *
     * @var array<int, string>
     */
    protected $dontFlash = [
        'current_password',
        'password',
        'password_confirmation',
    ];

    /**
     * Register the exception handling callbacks for the application.
     */
    public function register(): void
    {
        $this->reportable(function (Throwable $e) {
            //
        });
    }

    /**
     * Render an exception into an HTTP response.
     */
    public function render($request, Throwable $e): Response
    {
        // Handle API requests with JSON responses
        if ($request->is('api/*') || $request->expectsJson()) {
            return $this->handleApiException($request, $e);
        }
        return parent::render($request, $e);
    }

    /**
     * Handle API exceptions and return JSON responses.
     */
    protected function handleApiException(Request $request, Throwable $e): JsonResponse
    {
        // Route not found (404)
        if ($e instanceof NotFoundHttpException) {
            return response()->json([
                'message' => 'Route not found',
                'statusCode' => 404,
            ], 404);
        }
        // Method not allowed (405)
        if ($e instanceof MethodNotAllowedHttpException) {
            return response()->json([
                'message' => 'Method not allowed',
                'statusCode' => 405,
            ], 405);
        }
        // Authentication exception (401)
        if ($e instanceof AuthenticationException) {
            return response()->json([
                'message' => 'Unauthorized access',
                'statusCode' => 401,
            ], 401);
        }
        // Validation exception (422)
        if ($e instanceof ValidationException) {
            return response()->json([
                'message' => 'Validation failed' . $e->getMessage(),
                'statusCode' => 422,
            ], 422);
        }
        // Model not found (404)
        if ($e instanceof ModelNotFoundException) {
            return response()->json([
                'message' => 'Resource not found',
                'statusCode' => 404,
            ], 404);
        }
        // Throttle requests (429)
        if ($e instanceof ThrottleRequestsException) {
            return response()->json([
                'message' => 'Too many requests',
                'statusCode' => 429,
            ], 429);
        }
        // Token mismatch (419)
        if ($e instanceof TokenMismatchException) {
            return response()->json([
                'message' => 'Token mismatch',
                'statusCode' => 419,
            ], 419);
        }
        // Invalid signature (403)
        if ($e instanceof InvalidSignatureException) {
            return response()->json([
                'message' => 'Invalid signature',
                'statusCode' => 403,
            ], 403);
        }
        // HTTP exceptions
        if ($e instanceof HttpException) {
            $statusCode = $e->getStatusCode();
            $message = $e->getMessage() ?: $this->getDefaultMessage($statusCode);   
            return response()->json([
                'message' => $message,
                'statusCode' => $statusCode,
            ], $statusCode);
        }
        // Generic server error (500)
        $statusCode = 500;
        $message = 'Internal server error';
        // In development, show the actual error
        if (config('app.debug')) {
            $message = $e->getMessage();
        }
        return response()->json([
            'message' => $message,
            'statusCode' => $statusCode,
            'error' => 'An unexpected error occurred',
            'file' => config('app.debug') ? $e->getFile() : null,
            'line' => config('app.debug') ? $e->getLine() : null,
            'trace' => config('app.debug') ? $e->getTraceAsString() : null
        ], $statusCode);
    }

    /**
     * Get default message for HTTP status code.
     */
    protected function getDefaultMessage(int $statusCode): string
    {
        return match ($statusCode) {
            400 => 'Bad request',
            401 => 'Unauthorized',
            403 => 'Forbidden',
            404 => 'Not found',
            405 => 'Method not allowed',
            422 => 'Unprocessable entity',
            429 => 'Too many requests',
            500 => 'Internal server error',
            503 => 'Service unavailable',
            default => 'Error occurred'
        };
    }

    /**
     * Get default error description for HTTP status code.
     */
    protected function getDefaultError(int $statusCode): string
    {
        return match ($statusCode) {
            400 => 'The request is invalid or malformed',
            401 => 'Authentication is required to access this resource',
            403 => 'You do not have permission to access this resource',
            404 => 'The requested resource was not found',
            405 => 'The HTTP method is not allowed for this endpoint',
            422 => 'The request data is invalid or incomplete',
            429 => 'Rate limit exceeded. Please try again later',
            500 => 'An internal server error occurred',
            503 => 'The service is temporarily unavailable',
            default => 'An error occurred while processing the request'
        };
    }
}
