<?php
declare(strict_types=1);

namespace Tests\Unit\Api;

use Tests\TestCase;
use App\Core\App;
use App\Core\Request;
use App\Core\Response;
use App\Middleware\CorsMiddleware;

final class CorsMiddlewareTest extends TestCase
{
    private CorsMiddleware $middleware;

    protected function setUp(): void
    {
        parent::setUp();
        $this->middleware = new CorsMiddleware();

        $app = App::getInstance();
        $ref = new \ReflectionClass($app);
        $configProp = $ref->getProperty('config');
        $configProp->setAccessible(true);
        $config = $configProp->getValue($app);
        $config['api'] = [
            'cors' => [
                'allowed_origins' => ['http://localhost:3000', 'http://localhost:5173'],
                'allowed_methods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
                'allowed_headers' => ['Content-Type', 'Authorization', 'X-Requested-With', 'Accept'],
                'exposed_headers' => ['X-Request-Id'],
                'max_age' => 86400,
                'allow_credentials' => true,
            ],
        ];
        $configProp->setValue($app, $config);
    }

    public function testPassthroughCallsNext(): void
    {
        $request = $this->createMockRequest('GET', null);
        $called = false;

        $response = $this->middleware->handle($request, function ($req) use (&$called) {
            $called = true;
            return (new Response())->json(['ok' => true]);
        });

        $this->assertTrue($called);
    }

    public function testOptionsRequestReturns204(): void
    {
        $request = $this->createMockRequest('OPTIONS', 'http://localhost:3000');

        $response = $this->middleware->handle($request, function () {
            return (new Response())->json(['should_not_reach' => true]);
        });

        $ref = new \ReflectionClass($response);
        $statusProp = $ref->getProperty('statusCode');
        $statusProp->setAccessible(true);
        $this->assertEquals(204, $statusProp->getValue($response));
    }

    public function testCorsHeadersSetForAllowedOrigin(): void
    {
        $request = $this->createMockRequest('GET', 'http://localhost:3000');

        $response = $this->middleware->handle($request, function () {
            return (new Response())->json(['data' => 'test']);
        });

        $ref = new \ReflectionClass($response);
        $headersProp = $ref->getProperty('headers');
        $headersProp->setAccessible(true);
        $headers = $headersProp->getValue($response);

        $this->assertEquals('http://localhost:3000', $headers['Access-Control-Allow-Origin']);
        $this->assertEquals('true', $headers['Access-Control-Allow-Credentials']);
    }

    public function testNoCorsHeadersForDisallowedOrigin(): void
    {
        $request = $this->createMockRequest('GET', 'http://evil.com');

        $response = $this->middleware->handle($request, function () {
            return (new Response())->json(['data' => 'test']);
        });

        $ref = new \ReflectionClass($response);
        $headersProp = $ref->getProperty('headers');
        $headersProp->setAccessible(true);
        $headers = $headersProp->getValue($response);

        $this->assertNotEquals('http://evil.com', $headers['Access-Control-Allow-Origin'] ?? '');
    }

    private function createMockRequest(string $method, ?string $origin): Request
    {
        $_SERVER['REQUEST_METHOD'] = $method;
        $_SERVER['REQUEST_URI'] = '/api/v1/test';
        $_SERVER['SCRIPT_NAME'] = '/index.php';
        if ($origin !== null) {
            $_SERVER['HTTP_ORIGIN'] = $origin;
        } else {
            unset($_SERVER['HTTP_ORIGIN']);
        }
        $_GET = [];
        $_POST = [];
        $_FILES = [];
        $_COOKIE = [];

        return new Request();
    }
}
