<?php

namespace App\Exceptions;

use Throwable;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Validation\ValidationException;
use Illuminate\Auth\AuthenticationException;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
use App;

class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that are not reported.
     *
     * @var array
     */
    protected $dontReport = [
        \Illuminate\Auth\AuthenticationException::class,
        \Illuminate\Auth\Access\AuthorizationException::class,
        \Symfony\Component\HttpKernel\Exception\HttpException::class,
        \Illuminate\Database\Eloquent\ModelNotFoundException::class,
        \Illuminate\Validation\ValidationException::class,
        \Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class
    ];

    /**
     * A list of the inputs that are never flashed for validation exceptions.
     *
     * @var array
     */
    protected $dontFlash = [
        'password',
        'password_confirmation',
    ];

    /**
     * Report or log an exception.
     *
     * @param  Throwable $e
     *
     * @throws Throwable
     */
    public function report(Throwable $e)
    {
        parent::report($e);
    }

    /**
     * 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)
    {

        $customRes = $this->handleApiExceptions($e, $request);

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


    /**
     * Convert an authentication exception into a response.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Illuminate\Auth\AuthenticationException  $exception
     * @return \Symfony\Component\HttpFoundation\Response
     */
    protected function unauthenticated($request, AuthenticationException $exception)
    {

        if ($request->is('api/*')) {
            $data = [
                'error'   => 'not_logged',
                'message' => trans('response.not_logged'),
            ];
            return response()->json($data, 401);
        }

        return parent::unauthenticated($request, $exception);
    }



    /**
     * Create a response object from the given validation exception.
     *
     * @param  \Illuminate\Validation\ValidationException  $e
     * @param  \Illuminate\Http\Request  $request
     * @return \Symfony\Component\HttpFoundation\Response
     */
    protected function convertValidationExceptionToResponse(ValidationException $e, $request): Response
    {

        if ($request->is('api/*')) {
            $data = [
                'error'   => 'validation',
                'message' => trans('response.validation'),
                'errors'  => $e->errors(),
            ];
            return response()->json($data, $e->status);
        }

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


    /**
     * Handles custom exceptions for the API requests
     *
     * @param  Throwable $e
     * @param  Request $request
     * @return JsonResponse
     */
    private function handleApiExceptions(Throwable $e, Request $request): ?JsonResponse
    {

        //We only want to capture /api requests, all other request exceptions should be left alone
        if (!$request->is('api/*')) {
            return null;
        }
        if ($e instanceof ErrorException) {
            /** @var ErrorException $e */
            $data = [
                'error'   => 'unknown_error',
                'message' => trans('response.unknown_error'),
            ];
            if (App::environment() === 'local') {
                $data['message'] .= ' ' . $e->getMessage();
            }
            return response()->json($data, 500);
        }

        return null;
    }

    /**
     * Register the exception handling callbacks for the application.
     *
     * @return void
     */
    public function register(): void
    {
        $this->renderable(function (NotFoundHttpException $e, $request) {
            if ($request->is('api/*')) {
                $data = [
                    'error'   => 'route_not_found',
                    'message' => trans('response.route_not_found'),
                ];
                return response()->json($data, $e->getStatusCode());
            }
        });

        $this->renderable(function (\InvalidArgumentException $e, $request) {
            if ($request->is('api/*')) {
                $data = [
                    'error'   => 'validation',
                    'message' => $e->getMessage(),
                ];
                return response()->json($data, 400);
            }
        });

        $this->renderable(function (TokenInvalidException $e, $request) {
            if ($request->is('api/*')) {
                $data = [
                    'error'   => 'invalid_token',
                    'message' => trans('response.invalid_token'),
                ];
                return response()->json($data, 400);
            }
        });
    }
}
