<?php

namespace App\Exceptions;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\JsonResponse;
use Illuminate\Validation\ValidationException;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
use Throwable;

class ApiHandler extends ExceptionHandler
{
    /**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Throwable  $e
     * @return \Illuminate\Http\Response
     */
    public function render($request, Throwable $e)
    {
        // Only handle API requests
        if ($request->is('api/*')) {
            return $this->handleApiException($request, $e);
        }

        return parent::render($request, $e);
    }

    /**
     * Handle API exceptions and return standardized JSON responses.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Throwable  $exception
     * @return \Illuminate\Http\JsonResponse
     */
    private function handleApiException($request, Throwable $exception): JsonResponse
    {
        $exception = $this->prepareException($exception);

        if ($exception instanceof ValidationException) {
            return $this->convertValidationExceptionToResponse($exception, $request);
        }

        if ($exception instanceof AuthenticationException) {
            return $this->unauthenticated($request, $exception);
        }

        if ($exception instanceof AuthorizationException) {
            return $this->errorResponse(
                'Access forbidden. You do not have permission to perform this action.',
                ['error_code' => 'ACCESS_FORBIDDEN'],
                403
            );
        }

        if ($exception instanceof ModelNotFoundException) {
            $modelName = class_basename($exception->getModel());
            return $this->errorResponse(
                "{$modelName} not found.",
                ['error_code' => 'RESOURCE_NOT_FOUND'],
                404
            );
        }

        if ($exception instanceof NotFoundHttpException) {
            return $this->errorResponse(
                'The requested endpoint was not found.',
                ['error_code' => 'ENDPOINT_NOT_FOUND'],
                404
            );
        }

        if ($exception instanceof MethodNotAllowedHttpException) {
            return $this->errorResponse(
                'The HTTP method is not allowed for this endpoint.',
                ['error_code' => 'METHOD_NOT_ALLOWED'],
                405
            );
        }

        if ($exception instanceof TooManyRequestsHttpException) {
            return $this->errorResponse(
                'Too many requests. Please try again later.',
                ['error_code' => 'TOO_MANY_REQUESTS'],
                429
            );
        }

        // Default server error
        return $this->errorResponse(
            'An unexpected error occurred. Please try again.',
            [
                'error_code' => 'SERVER_ERROR',
                'trace' => config('app.debug') ? $exception->getTrace() : null
            ],
            500
        );
    }

    /**
     * Create a standardized error response.
     *
     * @param string $message
     * @param array $data
     * @param int $statusCode
     * @return \Illuminate\Http\JsonResponse
     */
    private function errorResponse(string $message, array $data = [], int $statusCode = 400): JsonResponse
    {
        $response = [
            'success' => false,
            'message' => $message,
        ];

        if (!empty($data)) {
            $response = array_merge($response, $data);
        }

        return response()->json($response, $statusCode);
    }

    /**
     * Convert a validation exception into a JSON response.
     *
     * @param  \Illuminate\Validation\ValidationException  $e
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\JsonResponse
     */
    protected function convertValidationExceptionToResponse(ValidationException $e, $request): JsonResponse
    {
        $errors = $e->errors();

        // Flatten error messages for better API response
        $formattedErrors = [];
        foreach ($errors as $field => $messages) {
            $formattedErrors[$field] = is_array($messages) ? $messages[0] : $messages;
        }

        return $this->errorResponse(
            'The given data was invalid.',
            [
                'error_code' => 'VALIDATION_FAILED',
                'errors' => $formattedErrors
            ],
            422
        );
    }

    /**
     * Convert an authentication exception into an unauthenticated response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Illuminate\Auth\AuthenticationException  $exception
     * @return \Illuminate\Http\JsonResponse
     */
    protected function unauthenticated($request, AuthenticationException $exception): JsonResponse
    {
        return $this->errorResponse(
            'Authentication required. Please provide a valid token.',
            ['error_code' => 'AUTHENTICATION_REQUIRED'],
            401
        );
    }
}
