<?php
declare(strict_types=1);

namespace Tests\Unit\Api;

use Tests\TestCase;
use App\Core\ApiController;
use App\Core\Request;
use App\Core\Response;
use App\Core\Exceptions\ValidationException;

final class ApiControllerTest extends TestCase
{
    private object $controller;

    protected function setUp(): void
    {
        parent::setUp();
        $this->controller = new class extends ApiController {
            public function __construct()
            {
                parent::__construct();
            }

            public function callSuccess($data, int $status = 200, array $meta = []): Response
            {
                return $this->successResponse($data, $status, $meta);
            }

            public function callError(string $message, int $status = 400, array $details = []): Response
            {
                return $this->errorResponse($message, $status, $details);
            }

            public function callPaginated(array $items, int $total, int $page, int $perPage): Response
            {
                return $this->paginatedResponse($items, $total, $page, $perPage);
            }
        };
    }

    public function testSuccessResponseStructure(): void
    {
        $response = $this->controller->callSuccess(['id' => 1, 'name' => 'Test']);
        $body = $this->decodeResponseBody($response);

        $this->assertTrue($body['success']);
        $this->assertEquals(['id' => 1, 'name' => 'Test'], $body['data']);
        $this->assertNull($body['errors']);
    }

    public function testSuccessResponseWithMeta(): void
    {
        $response = $this->controller->callSuccess(['id' => 1], 200, ['version' => 'v1']);
        $body = $this->decodeResponseBody($response);

        $this->assertTrue($body['success']);
        $this->assertEquals(['version' => 'v1'], $body['meta']);
    }

    public function testErrorResponseStructure(): void
    {
        $response = $this->controller->callError('Something went wrong', 422);
        $body = $this->decodeResponseBody($response);

        $this->assertFalse($body['success']);
        $this->assertNull($body['data']);
        $this->assertEquals('Something went wrong', $body['errors']['message']);
    }

    public function testErrorResponseWithDetails(): void
    {
        $details = ['field' => ['required']];
        $response = $this->controller->callError('Validation failed', 422, $details);
        $body = $this->decodeResponseBody($response);

        $this->assertFalse($body['success']);
        $this->assertEquals($details, $body['errors']['details']);
    }

    public function testPaginatedResponseStructure(): void
    {
        $items = [['id' => 1], ['id' => 2]];
        $response = $this->controller->callPaginated($items, 50, 1, 25);
        $body = $this->decodeResponseBody($response);

        $this->assertTrue($body['success']);
        $this->assertCount(2, $body['data']);
        $this->assertEquals(50, $body['meta']['total']);
        $this->assertEquals(1, $body['meta']['page']);
        $this->assertEquals(25, $body['meta']['per_page']);
        $this->assertEquals(2, $body['meta']['last_page']);
    }

    public function testPaginatedLastPageCalculation(): void
    {
        $response = $this->controller->callPaginated([], 101, 3, 10);
        $body = $this->decodeResponseBody($response);

        $this->assertEquals(11, $body['meta']['last_page']);
    }

    private function decodeResponseBody(Response $response): array
    {
        $ref = new \ReflectionClass($response);
        $bodyProp = $ref->getProperty('body');
        $bodyProp->setAccessible(true);
        return json_decode($bodyProp->getValue($response), true);
    }
}
