<?php

declare(strict_types=1);

use App\Framework\LiveComponents\Batch\BatchOperation;
use App\Framework\LiveComponents\ValueObjects\ActionParameters;

describe('BatchOperation', function () {
    it('creates operation from array', function () {
        $data = [
            'componentId' => 'counter:demo',
            'method' => 'increment',
            'params' => ['amount' => 5],
            'fragments' => ['counter-display'],
            'operationId' => 'op-1',
        ];

        $operation = BatchOperation::fromArray($data);

        expect($operation->componentId)->toBe('counter:demo');
        expect($operation->method)->toBe('increment');
        expect($operation->params)->toBe(['amount' => 5]);
        expect($operation->fragments)->toBe(['counter-display']);
        expect($operation->operationId)->toBe('op-1');
    });

    it('creates minimal operation', function () {
        $operation = new BatchOperation(
            componentId: 'stats:user',
            method: 'refresh'
        );

        expect($operation->componentId)->toBe('stats:user');
        expect($operation->method)->toBe('refresh');
        expect($operation->params)->toBe([]);
        expect($operation->fragments)->toBeNull();
        expect($operation->operationId)->toBeNull();
    });

    it('throws on empty component id', function () {
        expect(fn () => new BatchOperation('', 'method'))
            ->toThrow(InvalidArgumentException::class, 'Component ID cannot be empty');
    });

    it('throws on empty method', function () {
        expect(fn () => new BatchOperation('counter:demo', ''))
            ->toThrow(InvalidArgumentException::class, 'Method cannot be empty');
    });

    it('converts params to ActionParameters', function () {
        $operation = new BatchOperation(
            componentId: 'counter:demo',
            method: 'increment',
            params: ['amount' => 5, 'step' => 2]
        );

        $actionParams = $operation->getActionParameters();

        expect($actionParams)->toBeInstanceOf(ActionParameters::class);
        expect($actionParams->toArray())->toBe(['amount' => 5, 'step' => 2]);
    });

    it('checks if has fragments', function () {
        $withFragments = new BatchOperation('counter:demo', 'increment', fragments: ['display']);
        expect($withFragments->hasFragments())->toBeTrue();

        $withoutFragments = new BatchOperation('counter:demo', 'increment');
        expect($withoutFragments->hasFragments())->toBeFalse();

        $emptyFragments = new BatchOperation('counter:demo', 'increment', fragments: []);
        expect($emptyFragments->hasFragments())->toBeFalse();
    });

    it('gets fragments', function () {
        $operation = new BatchOperation(
            componentId: 'counter:demo',
            method: 'increment',
            fragments: ['counter-display', 'counter-controls']
        );

        expect($operation->getFragments())->toBe(['counter-display', 'counter-controls']);
    });

    it('converts to array', function () {
        $operation = new BatchOperation(
            componentId: 'counter:demo',
            method: 'increment',
            params: ['amount' => 5],
            fragments: ['display'],
            operationId: 'op-1'
        );

        $array = $operation->toArray();

        expect($array)->toBe([
            'componentId' => 'counter:demo',
            'method' => 'increment',
            'params' => ['amount' => 5],
            'fragments' => ['display'],
            'operationId' => 'op-1',
        ]);
    });
});
