<?php

namespace Tests\Unit\Middleware;

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

class ApiAuthenticatedRequestTest extends TestCase
{
    use RefreshDatabase;

    protected $tenancy = true;
    protected bool $tenancy_make_databases = false;

    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);
    }

    private function getResponse($request): Response
    {
        return $this->middleware->handle($request, function () {
            return response('ok');
        });
    }
}
