<?php

namespace Velis\Api\HttpExceptionHandler;

use Exception;
use Phalcon\Http\Message\ResponseStatusCodeInterface as ResponseStatusCode;
use Throwable;
use Velis\App;
use Velis\Debug;
use Velis\Lang;

/**
 * This is a base for HTTP Exceptions (exceptions that should be returned to the user as an API response).
 * All further exceptions should extend this class or at least use its interface.
 * In this class, we can decide whether exception should be logged to our Error Tracking system or not.
 *
 * @author Szymon Janaczek <szymon.janaczek@velistech.com>
 */
class HttpException extends Exception implements HttpExceptionInterface
{
    public function __construct(
        $message = '',
        $code = 0,
        protected ?string $error = null,
        protected ?array $details = null,
        protected ?int $httpCode = null,
        Throwable $previous = null
    ) {
        if ($message === '') {
            $message = Lang::get('GENERAL_ERROR_OCCURRED');
        }

        parent::__construct($message, $code, $previous);
    }

    public function getHttpCode(): int
    {
        $httpCode = $this->httpCode;

        if ($httpCode === null) {
            return ResponseStatusCode::STATUS_INTERNAL_SERVER_ERROR;
        }

        if ($httpCode < 100 || $httpCode > 599) {
            return ResponseStatusCode::STATUS_INTERNAL_SERVER_ERROR;
        }

        return $httpCode;
    }

    public function getError(): ?string
    {
        return $this->error;
    }

    public function getDetails(): ?array
    {
        return $this->details;
    }

    /**
     * Decide if we should report the exception to our Error Tracking system.
     */
    public function shouldReport(): bool
    {
        return $this->getHttpCode() >= ResponseStatusCode::STATUS_INTERNAL_SERVER_ERROR
                && App::$config->errorReporting->reportExceptions;
    }

    /**
     * Report an exception to our Error Tracking system.
     */
    public function report(?Throwable $originalException = null): void
    {
        if ($this->shouldReport()) {
            Debug::reportException($originalException ?? $this);
        }
    }
}
