<?php
namespace Tests\Unit\api;

use PHPUnit\Framework\TestCase;
use api\ApiRouter;
use Domain\Settings\SettingsRepository;

class ApiRouterTest extends TestCase
{
    private function createRouter(string $storedApiKey = 'test-api-key-123'): ApiRouter
    {
        $mockDb = $this->createMock(\medoo::class);
        $mockSettings = $this->createMock(SettingsRepository::class);
        $mockSettings->method('getSingleValue')
            ->with('api_key')
            ->willReturn($storedApiKey);

        return new ApiRouter($mockDb, $mockSettings);
    }

    public function testHandleReturns401WhenNoApiKey(): void
    {
        unset($_SERVER['HTTP_X_API_KEY']);
        $_GET['endpoint'] = 'orders';
        $_GET['action'] = 'list';

        $router = $this->createRouter();

        ob_start();
        $router->handle();
        $output = ob_get_clean();

        $this->assertSame(401, http_response_code());
        $json = json_decode($output, true);
        $this->assertSame('error', $json['status']);
        $this->assertSame('UNAUTHORIZED', $json['code']);
    }

    public function testHandleReturns401WhenWrongApiKey(): void
    {
        $_SERVER['HTTP_X_API_KEY'] = 'wrong-key';
        $_GET['endpoint'] = 'orders';
        $_GET['action'] = 'list';

        $router = $this->createRouter();

        ob_start();
        $router->handle();
        $output = ob_get_clean();

        $this->assertSame(401, http_response_code());
        $json = json_decode($output, true);
        $this->assertSame('UNAUTHORIZED', $json['code']);
    }

    public function testHandleReturns401WhenStoredKeyEmpty(): void
    {
        $_SERVER['HTTP_X_API_KEY'] = 'any-key';
        $_GET['endpoint'] = 'orders';
        $_GET['action'] = 'list';

        $router = $this->createRouter('');

        ob_start();
        $router->handle();
        $output = ob_get_clean();

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

    public function testHandleReturns400WhenMissingEndpoint(): void
    {
        $_SERVER['HTTP_X_API_KEY'] = 'test-api-key-123';
        unset($_GET['endpoint']);
        $_GET['action'] = 'list';
        $_GET['endpoint'] = '';

        $router = $this->createRouter();

        ob_start();
        $router->handle();
        $output = ob_get_clean();

        $this->assertSame(400, http_response_code());
        $json = json_decode($output, true);
        $this->assertSame('BAD_REQUEST', $json['code']);
    }

    public function testHandleReturns400WhenMissingAction(): void
    {
        $_SERVER['HTTP_X_API_KEY'] = 'test-api-key-123';
        $_GET['endpoint'] = 'orders';
        $_GET['action'] = '';

        $router = $this->createRouter();

        ob_start();
        $router->handle();
        $output = ob_get_clean();

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

    public function testHandleReturns404ForUnknownEndpoint(): void
    {
        $_SERVER['HTTP_X_API_KEY'] = 'test-api-key-123';
        $_GET['endpoint'] = 'unknown';
        $_GET['action'] = 'list';

        $router = $this->createRouter();

        ob_start();
        $router->handle();
        $output = ob_get_clean();

        $this->assertSame(404, http_response_code());
        $json = json_decode($output, true);
        $this->assertSame('NOT_FOUND', $json['code']);
    }

    public function testSendSuccessOutputsCorrectJson(): void
    {
        ob_start();
        ApiRouter::sendSuccess(['foo' => 'bar']);
        $output = ob_get_clean();

        $json = json_decode($output, true);
        $this->assertSame('ok', $json['status']);
        $this->assertSame('bar', $json['data']['foo']);
    }

    public function testSendErrorOutputsCorrectJson(): void
    {
        ob_start();
        ApiRouter::sendError('BAD_REQUEST', 'Test error', 400);
        $output = ob_get_clean();

        $this->assertSame(400, http_response_code());
        $json = json_decode($output, true);
        $this->assertSame('error', $json['status']);
        $this->assertSame('BAD_REQUEST', $json['code']);
        $this->assertSame('Test error', $json['message']);
    }

    public function testRequireMethodReturnsTrueForMatchingMethod(): void
    {
        $_SERVER['REQUEST_METHOD'] = 'GET';

        ob_start();
        $result = ApiRouter::requireMethod('GET');
        ob_get_clean();

        $this->assertTrue($result);
    }

    public function testRequireMethodReturnsFalseAndSendsErrorForMismatch(): void
    {
        $_SERVER['REQUEST_METHOD'] = 'POST';

        ob_start();
        $result = ApiRouter::requireMethod('GET');
        $output = ob_get_clean();

        $this->assertFalse($result);
        $this->assertSame(405, http_response_code());
        $json = json_decode($output, true);
        $this->assertSame('METHOD_NOT_ALLOWED', $json['code']);
    }

    protected function tearDown(): void
    {
        unset($_SERVER['HTTP_X_API_KEY']);
        unset($_SERVER['REQUEST_METHOD']);
        $_GET = [];
        http_response_code(200);
    }
}
