<?php

$app->error(
    function ($exception) use ($app) {
        $router = $app->router->getMatchedRoute();
        $request = $app->request;
        $app->logger->addItem("type_of_log", "app_exception");
        $app->logger->addItem('route_pattern', $router->getPattern());
        $app->logger->addItem('route_name', $router->getName());
        $app->logger->addItem('request_method', $request->getMethod());
        $app->logger->addArray('request_param_', $_REQUEST);
        $app->logger->addArray('request_header_', $request->getHeaders());
        $stackTrace = str_replace("\n", "||", $exception->getTraceAsString());

        $app->logger->addItem("stack_trace", $stackTrace);

        if (get_class($exception) == 'ValidationException') {
            $app->response->setStatusCode(460, "Error");
            $app->response->setJsonContent([
                'success' => false,
                "message" => "Validation Errors",
                'errors' => $exception->getMessages()
            ]);
            $app->logger->addItem("error_message", "Validation Errors");
            $app->logger->addItem("additional_error_messages", $exception->getMessages());

            $app->response->send();
        } else if (get_class($exception) == 'CustomErrorException') {
            $app->response->setStatusCode($exception->getStatusCode(), "Error");
            $content = [
                'success' => false,
                'message' => $exception->getMessages()
            ];
            $app->logger->addItem("error_message", $exception->getMessages());
            if (count($exception->getErrors()) > 0) {
                $content["errors"] = $exception->getErrors();
                $app->logger->addArray("additional_error_messages", $exception->getErrors());
            }

            $app->response->setJsonContent($content);

            $app->response->send();
        } else {
            \Sentry\captureException($exception);
            $app->response->setStatusCode(BaseResponse::UNEXPECTED_ERROR, "Error");
            $content = [
                'success' => false,
                'message' => $exception->getMessage()
            ];

            if (!$app->config['hideStacktrace']) {
                $content['stacktrace'] = $stackTrace;
            }

            $app->logger->addItem("error_message", $exception->getMessage());
            if (!empty($exception->errorInfo)) {
                $app->logger->addArray("additional_error_messages", $exception->errorInfo);
            }
            $app->response->setJsonContent($content);
            $app->response->send();
        }
        $app->logger->error();
        return false;
    }
);

set_error_handler(
    function ($err_severity, $err_msg, $err_file, $err_line, $err_context) use ($app) {
        switch ($err_severity) {
            case E_ERROR:
                throw new ErrorException($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_WARNING:
                throw new WarningException($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_PARSE:
                throw new ParseException($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_NOTICE:
                throw new NoticeException($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_CORE_ERROR:
                throw new CoreErrorException($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_CORE_WARNING:
                throw new CoreWarningException($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_COMPILE_ERROR:
                throw new CompileErrorException($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_COMPILE_WARNING:
                throw new CoreWarningException($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_USER_ERROR:
                throw new UserErrorException($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_USER_WARNING:
                throw new UserWarningException($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_USER_NOTICE:
                throw new UserNoticeException($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_STRICT:
                throw new StrictException($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_RECOVERABLE_ERROR:
                throw new RecoverableErrorException($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_DEPRECATED:
                throw new DeprecatedException($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_USER_DEPRECATED:
                throw new UserDeprecatedException($err_msg, 0, $err_severity, $err_file, $err_line);
        }
    }
);

register_shutdown_function(
    function () use ($app) {
        $error = error_get_last();
        if ($error['type'] === E_ERROR) {
            http_response_code(500);

            $router = $app->router->getMatchedRoute();
            $request = $app->request;

            $app->logger->addItem("type_of_log", "app_exception");
            $app->logger->addArray("error_", $error);
            if (!empty($request) && !empty($router)) {
                $app->logger->addItem('route_pattern', $router->getPattern());
                $app->logger->addItem('route_name', $router->getName());
                $app->logger->addItem('request_method', $request->getMethod());
                $app->logger->addArray('request_param_', $_REQUEST);
            }
            $app->logger->error();
        }
    }
);

class WarningException extends ErrorException
{
}
class ParseException extends ErrorException
{
}
class NoticeException extends ErrorException
{
}
class CoreErrorException extends ErrorException
{
}
class CoreWarningException extends ErrorException
{
}
class CompileErrorException extends ErrorException
{
}
class CompileWarningException extends ErrorException
{
}
class UserErrorException extends ErrorException
{
}
class UserWarningException extends ErrorException
{
}
class UserNoticeException extends ErrorException
{
}
class StrictException extends ErrorException
{
}
class RecoverableErrorException extends ErrorException
{
}
class DeprecatedException extends ErrorException
{
}
class UserDeprecatedException extends ErrorException
{
}
