<?php

namespace Dipper\Foundation\Exceptions;

use Exception;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Laravel\Lumen\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\HttpException;

class Handler extends ExceptionHandler
{
    const DEFAULT_MESSAGE = '请求出错，请稍后再试';
    const DEFAULT_STATUS_CODE = 400;

    /**
     * A list of the exception types that should not be reported.
     *
     * @var array
     */
    protected $dontReport = [
        AuthorizationException::class,
        HttpException::class,
        ModelNotFoundException::class,
        ValidationException::class,
    ];

    /**
     * Report or log an exception.
     *
     * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
     *
     * @param  \Exception  $e
     * @return void
     */
    public function report(Exception $e)
    {
        parent::report($e);
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Exception  $e
     * @return \Illuminate\Http\Response
     */
    public function render($request, Exception $e)
    {
        if ($this->isApiRequest($request)) {
            return $this->renderJson($e, $request);
        }

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

    /**
     * 判断是否是Api请求
     *
     * @param  \Illuminate\Http\Request $request
     *
     * @return bool
     */
    public function isApiRequest($request)
    {
        return $request->expectsJson() || Str::startsWith($request->server('HTTP_HOST'), 'api.') || $request->is(config('dipper.api.prefix') . '/*');
    }

    /**
     * @param $exception
     *
     * @return  \Illuminate\Http\JsonResponse
     */
    private function renderJson($exception, $request)
    {
        // TODO: needs refactoring..
        $statusCode = ($exception instanceof HttpException) ? $exception->getStatusCode() : self::DEFAULT_STATUS_CODE;

        // default response message
        $responseMessage['code'] = -1;
        $responseMessage['message'] = ($exception->getMessage() != '') ? $exception->getMessage() : self::DEFAULT_MESSAGE;
        $responseMessage['data'] = null;

        // If debugging enabled, add the exception class name, message and stack trace to response
        if (config('app.debug')) {
            $responseMessage['line'] = $exception->getLine();
            $responseMessage['file'] = $exception->getFile();
            $responseMessage['class'] = get_class($exception);
            $responseMessage['trace'] = explode("\n", $exception->getTraceAsString());
        }

        //-----------------------------
        if ($exception instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException) {
            $statusCode = 404;
            $responseMessage['message'] = '接口不存在';
        }

        if ($exception instanceof \Illuminate\Validation\ValidationException) {
            $statusCode = 422;
            $responseMessage['message'] = $exception->validator->errors()->first();
        }

        if ($exception instanceof \Illuminate\Auth\AuthenticationException) {
            $statusCode = 401;
            $responseMessage['message'] = '用户身份未认证';
        }

        if ($exception instanceof \Illuminate\Auth\Access\AuthorizationException) {
            $statusCode = 403;
            $responseMessage['message'] = '用户没有权限';
        }

        if ($exception instanceof \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException) {
            $statusCode = 405;
            $responseMessage['message'] = '请求方法错误';
        }

        if ($exception instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) {
            $statusCode = 404;
            $responseMessage['message'] = '数据不存在或已删除';
        }

        if ($exception instanceof \Dipper\Foundation\Exceptions\ExceptionAbstract) {
            $responseMessage['code'] = $exception->getCode();
            $responseMessage['data'] = $exception->getData();
        }

        // Return a JSON response with the response array and status code
        return response()->json($responseMessage, $statusCode);
    }

    /**
     * Convert an authentication exception into an unauthenticated response.
     *
     * @param  \Illuminate\Http\Request                 $request
     * @param  \Illuminate\Auth\AuthenticationException $exception
     *
     * @return \Illuminate\Http\Response
     */
    protected function unauthenticated($request, AuthenticationException $exception)
    {
        if ($this->isApiRequest($request)) {
            return response()->json([
                'code' => false,
                'message' => '用户身份未认证',
                'result' => null,
            ], 401);
        }

        return redirect()->guest('/');
    }
}
