<?php
namespace app;

use core\exception\AuthException;
use core\exception\ServerException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\exception\RouteNotFoundException;
use think\exception\ValidateException;
use think\Response;
use Throwable;

/**
 * 应用异常处理类
 */
class ExceptionHandle extends Handle
{
    /**
     * 不需要记录信息（日志）的异常类列表
     * @var array
     */
    protected $ignoreReport = [
        HttpException::class,
        HttpResponseException::class,
        ModelNotFoundException::class,
        DataNotFoundException::class,
        ValidateException::class,
    ];

    /**
     * 记录异常信息（包括日志或者其它方式记录）
     *
     * @access public
     * @param  Throwable $exception
     * @return void
     */
    public function report(Throwable $exception): void
    {
        // 使用内置的方式记录异常日志
        parent::report($exception);
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @access public
     * @param \think\Request   $request
     * @param Throwable $e
     * @return Response
     */
    public function render($request, Throwable $e): Response
    {
        // 添加自定义异常处理机制
        $massageData = env('app_debug', false) ? [
            'file' => $e->getFile(),
            'line' => $e->getLine(),
            'message' => $e->getMessage(),
            'trace' => $e->getTrace(),
            'previous' => $e->getPrevious(),
        ] : [];


        if ($e instanceof DbException) {
            return fail(get_lang('DATA_GET_FAIL').':'.$e->getMessage(), [
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'message' => $e->getMessage(),
                'trace' => $e->getTrace(),
                'previous' => $e->getPrevious(),
            ]);
        } elseif ($e instanceof ValidateException) {
            return fail($e->getMessage());
        } else if($e instanceof AuthException){
            return fail($e->getMessage(), [],0, $e->getCode());
        } else if($e instanceof ServerException){
            return fail($e->getMessage(), [],0, $e->getCode());
        } else if ($e instanceof HttpException) {
            return fail($e->getMessage(), [], $e->getCode(), $e->getStatusCode());
        } else if ($e instanceof RouteNotFoundException) {
            return fail('当前访问路由未定义或不匹配 路由地址：' . request()->baseUrl(), [], 404, 404);
        } else if($e instanceof \RuntimeException){
            return fail($e->getMessage(), $massageData);
        } else {
            return $this->handleException($e);
        }
//        // 添加自定义异常处理机制
//
//        // 其他错误交给系统处理
//        return parent::render($request, $e);
    }

    private function handleException(Throwable $e) {
        // 处理控制器或方法不存在的异常，返回 404
        $message = $e->getMessage();
        if (strpos($message, 'method not exists') !== false 
            || strpos($message, 'controller not exists') !== false
            || strpos($message, 'class not exists') !== false) {
            return fail('404 Not Found', [], 0, 404);
        }

        // 添加自定义异常处理机制
        if (strpos($e->getMessage(), 'open_basedir') !== false) {
            return fail('OPEN_BASEDIR_ERROR');
        }
        if (strpos($e->getMessage(), 'Allowed memory size of') !== false) {
            return fail('PHP_SCRIPT_RUNNING_OUT_OF_MEMORY');
        }
        if (preg_match('/^(fopen|file_get_contents|file_put_contents|include|require)\((.+?)\):.*Permission denied/', $e->getMessage(), $matches)) {
            $filePath = $matches[2]; // 提取出来的文件路径
            return fail("请检查文件{$filePath}是否存在或权限是否正确");
        }
        $trace = array_map(function ($class){
            return str_replace('\\', '/', $class);
        }, array_column($e->getTrace(), 'class'));
        $debug = env("APP_DEBUG", false);

        return fail("{$trace[0]}第{$e->getLine()}行出现异常，异常信息：" .$e->getMessage(), $debug ? $e->getTrace() : []);
    }

}
