<?php

declare(strict_types=1);

use App\Framework\Http\Status;

describe('Batch Endpoint Integration', function () {
    it('handles valid batch request', function () {
        $requestData = [
            'operations' => [
                [
                    'componentId' => 'counter:demo',
                    'method' => 'increment',
                    'params' => ['amount' => 5],
                    'operationId' => 'op-1',
                ],
                [
                    'componentId' => 'stats:user',
                    'method' => 'refresh',
                    'operationId' => 'op-2',
                ],
            ],
        ];

        $response = $this->post('/live-component/batch', $requestData);

        expect($response->status)->toBe(Status::OK);

        $data = $response->jsonData;
        expect($data)->toHaveKey('results');
        expect($data)->toHaveKey('total_operations');
        expect($data)->toHaveKey('success_count');
        expect($data)->toHaveKey('failure_count');

        expect($data['total_operations'])->toBe(2);
        expect($data['results'])->toHaveCount(2);
    });

    it('returns error for invalid batch request format', function () {
        $requestData = [
            'invalid' => 'format',
        ];

        $response = $this->post('/live-component/batch', $requestData);

        expect($response->status)->toBe(Status::BAD_REQUEST);

        $data = $response->jsonData;
        expect($data)->toHaveKey('error');
        expect($data)->toHaveKey('error_code');
        expect($data['error_code'])->toBe('INVALID_BATCH_REQUEST');
    });

    it('returns error for empty operations', function () {
        $requestData = [
            'operations' => [],
        ];

        $response = $this->post('/live-component/batch', $requestData);

        expect($response->status)->toBe(Status::BAD_REQUEST);
        expect($response->jsonData['error_code'])->toBe('INVALID_BATCH_REQUEST');
    });

    it('returns error for too many operations', function () {
        $operations = [];
        for ($i = 0; $i < 51; $i++) {
            $operations[] = [
                'componentId' => "component:$i",
                'method' => 'action',
            ];
        }

        $requestData = ['operations' => $operations];

        $response = $this->post('/live-component/batch', $requestData);

        expect($response->status)->toBe(Status::BAD_REQUEST);
        expect($response->jsonData['error'])->toContain('cannot exceed 50 operations');
    });

    it('handles partial failures gracefully', function () {
        $requestData = [
            'operations' => [
                [
                    'componentId' => 'counter:demo',
                    'method' => 'increment',
                    'operationId' => 'op-1',
                ],
                [
                    'componentId' => 'invalid:component',
                    'method' => 'action',
                    'operationId' => 'op-2',
                ],
                [
                    'componentId' => 'stats:user',
                    'method' => 'refresh',
                    'operationId' => 'op-3',
                ],
            ],
        ];

        $response = $this->post('/live-component/batch', $requestData);

        expect($response->status)->toBe(Status::OK);

        $data = $response->jsonData;
        expect($data['total_operations'])->toBe(3);
        expect($data['success_count'])->toBeGreaterThanOrEqual(1);
        expect($data['failure_count'])->toBeGreaterThanOrEqual(1);

        // Check that results preserve operation IDs
        $operationIds = array_column($data['results'], 'operationId');
        expect($operationIds)->toContain('op-1');
        expect($operationIds)->toContain('op-2');
        expect($operationIds)->toContain('op-3');
    });

    it('supports fragment-based updates in batch', function () {
        $requestData = [
            'operations' => [
                [
                    'componentId' => 'counter:demo',
                    'method' => 'increment',
                    'fragments' => ['counter-display'],
                    'operationId' => 'op-1',
                ],
            ],
        ];

        $response = $this->post('/live-component/batch', $requestData);

        expect($response->status)->toBe(Status::OK);

        $data = $response->jsonData;
        $result = $data['results'][0];

        if ($result['success']) {
            // If fragments available, should have fragments instead of html
            if (isset($result['fragments'])) {
                expect($result['fragments'])->toBeArray();
                expect($result)->not->toHaveKey('html');
            }
        }
    });

    it('preserves state and events in batch response', function () {
        $requestData = [
            'operations' => [
                [
                    'componentId' => 'counter:demo',
                    'method' => 'increment',
                    'params' => ['amount' => 5],
                    'operationId' => 'op-1',
                ],
            ],
        ];

        $response = $this->post('/live-component/batch', $requestData);

        expect($response->status)->toBe(Status::OK);

        $result = $response->jsonData['results'][0];

        if ($result['success']) {
            expect($result)->toHaveKey('state');
            expect($result)->toHaveKey('events');
            expect($result['state'])->toBeArray();
            expect($result['events'])->toBeArray();
        }
    });

    it('handles concurrent batch requests independently', function () {
        $request1 = [
            'operations' => [
                ['componentId' => 'counter:demo', 'method' => 'increment', 'operationId' => 'req1-op1'],
            ],
        ];

        $request2 = [
            'operations' => [
                ['componentId' => 'stats:user', 'method' => 'refresh', 'operationId' => 'req2-op1'],
            ],
        ];

        $response1 = $this->post('/live-component/batch', $request1);
        $response2 = $this->post('/live-component/batch', $request2);

        expect($response1->status)->toBe(Status::OK);
        expect($response2->status)->toBe(Status::OK);

        expect($response1->jsonData['results'][0]['operationId'])->toBe('req1-op1');
        expect($response2->jsonData['results'][0]['operationId'])->toBe('req2-op1');
    });
});
