<?php

namespace MintyPHP\Tests\Http;

use MintyPHP\Debugger;
use MintyPHP\Http\ErrorHandler;
use MintyPHP\Http\RequestContext;
use PHPUnit\Framework\TestCase;

class ErrorHandlerTest extends TestCase
{
    private array $serverBackup = [];
    private int $errorReportingBackup = 0;
    private string|false $vendorIssueModeBackup = false;

    protected function setUp(): void
    {
        $this->serverBackup = $_SERVER;
        $this->errorReportingBackup = error_reporting();
        error_reporting(E_ALL);
        $this->vendorIssueModeBackup = getenv('APP_VENDOR_PHP_ISSUES_MODE');
        RequestContext::resetForTests();
        Debugger::$enabled = false;
        header_remove();
        http_response_code(200);
    }

    protected function tearDown(): void
    {
        $_SERVER = $this->serverBackup;
        error_reporting($this->errorReportingBackup);
        if ($this->vendorIssueModeBackup === false) {
            putenv('APP_VENDOR_PHP_ISSUES_MODE');
        } else {
            putenv('APP_VENDOR_PHP_ISSUES_MODE=' . $this->vendorIssueModeBackup);
        }
        RequestContext::resetForTests();
        Debugger::$enabled = false;
        header_remove();
    }

    /**
     * @runInSeparateProcess
     */
    public function testHandleExceptionReturnsJsonForApiRequestsWithRequestId(): void
    {
        $_SERVER['REQUEST_METHOD'] = 'GET';
        $_SERVER['REQUEST_URI'] = '/api/v1/ping';
        $_SERVER['HTTP_X_REQUEST_ID'] = '123e4567-e89b-12d3-a456-426614174000';

        $this->expectOutputRegex('/^(?:(?!<html).)*"error_code":"internal_error".*"request_id":"123e4567-e89b-12d3-a456-426614174000".*$/s');

        ErrorHandler::handleException(new \RuntimeException('API failure'));

        $this->assertSame(500, http_response_code());
    }

    /**
     * @runInSeparateProcess
     */
    public function testHandleExceptionRendersProdPageInWebWhenDebugDisabled(): void
    {
        $_SERVER['REQUEST_METHOD'] = 'GET';
        $_SERVER['REQUEST_URI'] = '/admin/users';
        $_SERVER['HTTP_X_REQUEST_ID'] = '123e4567-e89b-12d3-a456-426614174111';

        $this->expectOutputRegex('/^(?=.*<html lang="en">)(?=.*Back to start)(?=.*123e4567-e89b-12d3-a456-426614174111)(?!.*panel-exception).*$/s');

        ErrorHandler::handleException(new \RuntimeException('Web failure'));

        $this->assertSame(500, http_response_code());
    }

    /**
     * @runInSeparateProcess
     */
    public function testHandleExceptionKeepsExistingErrorStatusCode(): void
    {
        $_SERVER['REQUEST_METHOD'] = 'GET';
        $_SERVER['REQUEST_URI'] = '/admin/settings';
        http_response_code(500);

        $this->expectOutputRegex('/500/');

        ErrorHandler::handleException(new \RuntimeException('Status flow'));

        $this->assertSame(500, http_response_code());
    }

    public function testHandleErrorThrowsForVendorDeprecationInStrictMode(): void
    {
        putenv('APP_VENDOR_PHP_ISSUES_MODE=strict');

        $this->expectException(\ErrorException::class);
        ErrorHandler::handleError(E_DEPRECATED, 'deprecated', '/var/www/vendor/mintyphp/core/src/Router.php', 69);
    }

    public function testHandleErrorSuppressesVendorDeprecationsWhenConfigured(): void
    {
        putenv('APP_VENDOR_PHP_ISSUES_MODE=suppress_deprecations');

        ErrorHandler::handleError(E_DEPRECATED, 'deprecated', '/var/www/vendor/mintyphp/core/src/Router.php', 69);
        $this->addToAssertionCount(1);
    }

    public function testHandleErrorSuppressesVendorWarningsOnlyInWarningMode(): void
    {
        putenv('APP_VENDOR_PHP_ISSUES_MODE=suppress_deprecations');

        try {
            ErrorHandler::handleError(E_WARNING, 'warning', '/var/www/vendor/mintyphp/core/src/Router.php', 69);
            $this->fail('Expected ErrorException for vendor warning in suppress_deprecations mode.');
        } catch (\ErrorException) {
            // expected
        }

        putenv('APP_VENDOR_PHP_ISSUES_MODE=suppress_deprecations_warnings');
        ErrorHandler::handleError(E_WARNING, 'warning', '/var/www/vendor/mintyphp/core/src/Router.php', 69);
        $this->addToAssertionCount(1);
    }

    public function testHandleErrorNeverSuppressesNonVendorWarnings(): void
    {
        putenv('APP_VENDOR_PHP_ISSUES_MODE=suppress_deprecations_warnings');

        $this->expectException(\ErrorException::class);
        ErrorHandler::handleError(E_WARNING, 'warning', '/var/www/core/Http/ErrorHandler.php', 69);
    }
}
