<?php
namespace Tests\Unit\api\Controllers;

use PHPUnit\Framework\TestCase;
use api\Controllers\DictionariesApiController;
use Domain\Attribute\AttributeRepository;
use Domain\ShopStatus\ShopStatusRepository;
use Domain\Transport\TransportRepository;
use Domain\PaymentMethod\PaymentMethodRepository;

class DictionariesApiControllerTest extends TestCase
{
    private $mockStatusRepo;
    private $mockTransportRepo;
    private $mockPaymentRepo;
    private $mockAttrRepo;
    private $controller;

    protected function setUp(): void
    {
        $this->mockStatusRepo = $this->createMock(ShopStatusRepository::class);
        $this->mockTransportRepo = $this->createMock(TransportRepository::class);
        $this->mockPaymentRepo = $this->createMock(PaymentMethodRepository::class);
        $this->mockAttrRepo = $this->createMock(AttributeRepository::class);

        $this->controller = new DictionariesApiController(
            $this->mockStatusRepo,
            $this->mockTransportRepo,
            $this->mockPaymentRepo,
            $this->mockAttrRepo
        );

        $_SERVER['REQUEST_METHOD'] = 'GET';
    }

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

    // --- statuses ---

    public function testStatusesReturnsFormattedList(): void
    {
        $this->mockStatusRepo->method('allStatuses')
            ->willReturn([
                0 => 'Nowe',
                1 => 'Opłacone',
                4 => 'W realizacji',
                6 => 'Wysłane',
            ]);

        ob_start();
        $this->controller->statuses();
        $output = ob_get_clean();

        $json = json_decode($output, true);
        $this->assertSame('ok', $json['status']);
        $this->assertCount(4, $json['data']);
        $this->assertSame(0, $json['data'][0]['id']);
        $this->assertSame('Nowe', $json['data'][0]['name']);
        $this->assertSame(6, $json['data'][3]['id']);
        $this->assertSame('Wysłane', $json['data'][3]['name']);
    }

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

        ob_start();
        $this->controller->statuses();
        $output = ob_get_clean();

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

    // --- transports ---

    public function testTransportsReturnsFormattedList(): void
    {
        $this->mockTransportRepo->method('allActive')
            ->willReturn([
                ['id' => 1, 'name_visible' => 'InPost Paczkomat', 'cost' => '12.99'],
                ['id' => 2, 'name_visible' => 'Kurier DPD', 'cost' => '15.00'],
            ]);

        ob_start();
        $this->controller->transports();
        $output = ob_get_clean();

        $json = json_decode($output, true);
        $this->assertSame('ok', $json['status']);
        $this->assertCount(2, $json['data']);
        $this->assertSame(1, $json['data'][0]['id']);
        $this->assertSame('InPost Paczkomat', $json['data'][0]['name']);
        $this->assertSame(12.99, $json['data'][0]['cost']);
    }

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

        ob_start();
        $this->controller->transports();
        $output = ob_get_clean();

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

    // --- payment_methods ---

    public function testPaymentMethodsReturnsFormattedList(): void
    {
        $this->mockPaymentRepo->method('allActive')
            ->willReturn([
                ['id' => 1, 'name' => 'Przelew bankowy'],
                ['id' => 2, 'name' => 'Przelewy24'],
                ['id' => 3, 'name' => 'Przy odbiorze'],
            ]);

        ob_start();
        $this->controller->payment_methods();
        $output = ob_get_clean();

        $json = json_decode($output, true);
        $this->assertSame('ok', $json['status']);
        $this->assertCount(3, $json['data']);
        $this->assertSame(1, $json['data'][0]['id']);
        $this->assertSame('Przelew bankowy', $json['data'][0]['name']);
    }

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

        ob_start();
        $this->controller->payment_methods();
        $output = ob_get_clean();

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

    // --- attributes ---

    public function testAttributesReturnsFormattedList(): void
    {
        $this->mockAttrRepo->method('listForApi')
            ->willReturn([
                [
                    'id' => 5,
                    'type' => 0,
                    'status' => 1,
                    'names' => ['pl' => 'Rozmiar', 'en' => 'Size'],
                    'values' => [
                        [
                            'id' => 12,
                            'names' => ['pl' => 'M', 'en' => 'M'],
                            'is_default' => 1,
                            'impact_on_the_price' => null,
                        ],
                    ],
                ],
            ]);

        ob_start();
        $this->controller->attributes();
        $output = ob_get_clean();

        $json = json_decode($output, true);
        $this->assertSame('ok', $json['status']);
        $this->assertCount(1, $json['data']);
        $this->assertSame(5, $json['data'][0]['id']);
        $this->assertSame('Rozmiar', $json['data'][0]['names']['pl']);
        $this->assertCount(1, $json['data'][0]['values']);
        $this->assertSame(12, $json['data'][0]['values'][0]['id']);
    }

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

        ob_start();
        $this->controller->attributes();
        $output = ob_get_clean();

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