<?php

namespace Tests\Feature;

use Tests\TestCase;

class SiteReadinessRouteTest extends TestCase
{
    /** @var string|null Original $_SERVER['REQUEST_URI'] value before the test suite runs */
    private ?string $originalRequestUri = null;

    /**
     * Override createApplication so the test app also has the `twig` service
     * bound, which is required by AdminUserMiddleware.
     *
     * Background: PHPUnit's bootstrap (core/includes/header.inc.php) binds twig
     * on Application instance A via App::instance('twig', ...). This test class
     * inherits TestCase::createApplication() which uses plain `require` on
     * bootstrap/app.php, creating a fresh Application instance B. Because
     * bootstrap/app.php was already loaded with `require_once` by container.php,
     * there is no static singleton — `require` genuinely re-executes it and
     * returns a new Application each time, so twig is absent in instance B.
     *
     * The fix: after booting instance B's console kernel (which also re-runs
     * AppServiceProvider::boot but with a `require_once` guard that silently
     * skips twig.php), we re-include twig.php with a plain `require` so it
     * runs in the correct facade context and calls App::instance('twig', $twig)
     * against the active (instance B) container.
     */
    public function createApplication()
    {
        $app = parent::createApplication();

        if (!$app->bound('twig')) {
            // Re-run twig.php (plain require, not require_once) so it executes in
            // the context of the new app and calls App::instance('twig', $twig).
            require base_path('core/includes/twig.php');
            // Register custom Twig functions (config(), vite(), etc.) that the admin
            // layout depends on. Both AppServiceProvider::boot() and TwigHelper use
            // require_once, which silently skips re-execution after the PHPUnit
            // bootstrap has already loaded the file — so we use plain require here.
            $twig = $app->make('twig');
            require base_path('core/includes/functions.twig.php');
        }

        return $app;
    }

    protected function setUp(): void
    {
        parent::setUp();
        // Save the original REQUEST_URI so tearDown can restore it cleanly.
        $this->originalRequestUri = $_SERVER['REQUEST_URI'] ?? null;

        // HandleExceptions converts PHP warnings to ErrorException in test env.
        // Authenticate::class reads $_SERVER['REQUEST_URI'] to build the redirect
        // URL — set a safe value so the warning is suppressed and a redirect is
        // returned rather than a 500.
        $_SERVER['REQUEST_URI'] = '/admin/site-readiness';
    }

    protected function tearDown(): void
    {
        // Restore REQUEST_URI to avoid leaking into later test classes.
        if ($this->originalRequestUri === null) {
            unset($_SERVER['REQUEST_URI']);
        } else {
            $_SERVER['REQUEST_URI'] = $this->originalRequestUri;
        }

        unset($_SESSION['adminId']);
        parent::tearDown();
    }

    /**
     * Unauthenticated requests must not reach the controller.
     *
     * The `auth` middleware group includes Authenticate::class, which checks
     * $_SESSION['adminId']. Without it, the middleware throws
     * AuthenticationException, which redirects to the admin login page (302).
     * A 200 must never be returned.
     */
    public function test_unauthenticated_request_is_blocked(): void
    {
        unset($_SESSION['adminId']);

        $response = $this->get('/admin/site-readiness');

        $this->assertNotEquals(200, $response->getStatusCode(), 'Unauthenticated request should not return 200');
        $response->assertStatus(302);
    }

    /**
     * The mtc. admin (session adminId === MTCADMIN_USERID) must reach the controller
     * and the admin chrome (AdminUserMiddleware + layouts/admin.twig) must render.
     *
     * Asserts a genuine 200 with page content — not merely "not 302/403" — so a
     * 500 or blank response would also fail this test.
     */
    public function test_mtc_admin_can_view(): void
    {
        if (!defined('MTCADMIN_USERID')) {
            $this->markTestSkipped('MTCADMIN_USERID not defined in test environment');
        }

        $_SESSION['adminId'] = (int) \MTCADMIN_USERID;

        $response = $this->get('/admin/site-readiness');

        $response->assertStatus(200);
        $response->assertSee('Site Readiness');
    }
}
