<?php

namespace Tests\Feature;

use Illuminate\Support\Facades\Route;
use PHPUnit\Framework\Attributes\DataProvider;
use Tests\TestCase;

/**
 * The /api/v1 surface was removed. It carried an authentication bypass
 * (AuthOtpController::verify accepted a constant '0000' in the default mode and
 * minted a Sanctum token for any active user matching a phone number), an
 * unauthenticated academy-wide push broadcast, an attendance write with no
 * authorization, and several endpoints whose ownership checks were inverted or
 * absent. Rather than audit twenty-four controllers, the surface was deleted.
 *
 * This test exists so it cannot come back by accident — a re-added route file or
 * a stray controller fails here rather than in production.
 */
class MobileApiRemovedTest extends TestCase
{
    public static function removedEndpoints(): array
    {
        return [
            'otp request' => ['post', '/api/v1/auth/otp/request'],
            'otp verify — the bypass' => ['post', '/api/v1/auth/otp/verify'],
            'app config' => ['get', '/api/v1/app/config'],
            'push broadcast' => ['post', '/api/v1/broadcast/send'],
            'absence write' => ['post', '/api/v1/absences/report'],
            'payment initiate' => ['post', '/api/v1/payments/initiate'],
            'health' => ['get', '/api/v1/health'],
        ];
    }

    #[DataProvider('removedEndpoints')]
    public function test_removed_endpoint_is_not_routable(string $method, string $uri): void
    {
        $status = $this->{$method}($uri)->getStatusCode();

        // 404 for GET; 405 for the write verbs, because Route::fallback is
        // registered for GET only, so a POST to an unrouted path matches the URI
        // but not the method. Both mean "nothing serves this".
        $this->assertContains(
            $status,
            [404, 405],
            "{$uri} answered {$status}; the mobile API must stay removed."
        );
    }

    public function test_no_route_is_registered_under_the_api_prefix(): void
    {
        $apiRoutes = collect(Route::getRoutes()->getRoutes())
            ->map(fn ($route) => $route->uri())
            ->filter(fn (string $uri) => str_starts_with($uri, 'api/'))
            ->values()
            ->all();

        $this->assertSame([], $apiRoutes, 'Routes are registered under api/: '.implode(', ', $apiRoutes));
    }

    /**
     * The website page builder's fallback answers for any unrouted path, so
     * without a reserved-prefix guard a deleted endpoint returns a 200 HTML page
     * instead of 404 — which would have made the assertions above pass for the
     * wrong reason if they only checked "not 200".
     */
    public function test_reserved_prefixes_are_not_answered_by_the_page_builder_fallback(): void
    {
        foreach (['api/anything', 'app/anything', 'livewire/anything', 'admin/anything'] as $uri) {
            $this->assertSame(404, $this->get('/'.$uri)->getStatusCode(), "{$uri} should 404");
        }
    }
}
