<?php

namespace Tests\Feature\Middleware;

use App\Master\Models\ApiToken;
use Illuminate\Support\Facades\Bus;
use Mtc\MercuryDataModels\Jobs\TrackApiRequest;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Http\Request;
use App\Http\Middleware\ApiAuthenticatedRequest;
use Tests\DatabaseTestCase;

class ApiAuthenticatedRequestTest extends DatabaseTestCase
{

    #[\Override]
    protected function setUp(): void
    {
        parent::setUp();
        Bus::fake();
        $this->middleware = new ApiAuthenticatedRequest();
    }

    public function testDeniesAccessIfNoAuthorizationHeader(): void
    {
        $request = Request::create('/dummy', 'GET');
        $response = $this->getResponse($request);

        $this->assertEquals(401, $response->getStatusCode());
        $this->assertStringContainsString('Access Denied', $response->getContent());
    }

    public function testDeniesAccessWithInvalidToken(): void
    {
        $request = Request::create('/dummy', 'GET');
        $request->headers->set('Authorization', 'Bearer invalidtoken');
        $response = $this->getResponse($request);

        $this->assertEquals(401, $response->getStatusCode());
        $this->assertStringContainsString('Access Denied', $response->getContent());
    }

    public function testDeniesAccessWithExpiredToken(): void
    {
        tenant()->saveQuietly();
        $apiToken = ApiToken::factory()->expired()->create();
        $apiToken->apiUser->tenants()->attach(tenant('id'));

        $request = Request::create('/dummy', 'GET');
        $request->headers->set('Authorization', 'Bearer ' . $apiToken->token);

        $response = $this->getResponse($request);

        $this->assertEquals(401, $response->getStatusCode());
        $this->assertStringContainsString('Access Denied', $response->getContent());
    }

    public function testDeniesAccessIfTokenHasNoTenantAccess(): void
    {
        tenant()->saveQuietly();
        $apiToken = ApiToken::factory()->create();
        $apiToken->apiUser->tenants()->attach('some-other-tenant');

        $request = Request::create('/dummy', 'GET');
        $request->headers->set('Authorization', 'Bearer ' . $apiToken->token);

        $response = $this->getResponse($request);

        $this->assertEquals(401, $response->getStatusCode());
    }

    public function testAllowsAccessWithValidToken(): void
    {
        tenant()->saveQuietly();
        $apiToken = ApiToken::factory()->create();
        $apiToken->apiUser->tenants()->attach(tenant('id'));

        $request = Request::create('/dummy', 'GET');
        $request->headers->set('Authorization', 'Bearer ' . $apiToken->token);
        $response = $this->getResponse($request);

        $this->assertEquals(200, $response->getStatusCode());
    }

    public function testDispatchesTrackApiRequestJob(): void
    {
        tenant()->saveQuietly();
        $apiToken = ApiToken::factory()->create();
        $apiToken->apiUser->tenants()->attach(tenant('id'));

        $request = Request::create('/dummy', 'POST', ['foo' => 'bar']);
        $request->headers->set('Authorization', 'Bearer ' . $apiToken->token);

        $middleware = new ApiAuthenticatedRequest();
        $middleware->handle($request, fn() => response('ok'));

        Bus::assertDispatched(TrackApiRequest::class);
    }

    public function testAllowsExportMapAccessWithQueryParameterKey(): void
    {
        tenant()->saveQuietly();
        $apiToken = ApiToken::factory()->create();
        $apiToken->apiUser->tenants()->attach(tenant('id'));

        $request = Request::create('/dummy?key=' . $apiToken->token, 'GET');
        $response = $this->getResponse($request, 'export-map');

        $this->assertEquals(200, $response->getStatusCode());
    }

    public function testAllowsExportMapAccessWithBearerToken(): void
    {
        tenant()->saveQuietly();
        $apiToken = ApiToken::factory()->create();
        $apiToken->apiUser->tenants()->attach(tenant('id'));

        $request = Request::create('/dummy', 'GET');
        $request->headers->set('Authorization', 'Bearer ' . $apiToken->token);
        $response = $this->getResponse($request, 'export-map');

        $this->assertEquals(200, $response->getStatusCode());
    }

    public function testDeniesExportMapAccessWithInvalidKey(): void
    {
        $request = Request::create('/dummy?key=invalidtoken', 'GET');
        $response = $this->getResponse($request, 'export-map');

        $this->assertEquals(401, $response->getStatusCode());
    }

    private function getResponse($request, ?string $legacyScenario = null): Response
    {
        return $this->middleware->handle($request, fn() => response('ok'), $legacyScenario);
    }
}
