<?php

use helpers\economic_invoice_draft;

if (!class_exists('EconomicInvoiceDraftBatchingProbe')) {
    class EconomicInvoiceDraftBatchingProbe extends economic_invoice_draft
    {
        public array $sentBatches = [];

        protected function sendDraftLines(array $draft_lines): object
        {
            $this->sentBatches[] = $draft_lines;
            return (object)['lines' => $draft_lines];
        }
    }
}

if (!class_exists('EconomicInvoiceDraftFailingBatchingProbe')) {
    class EconomicInvoiceDraftFailingBatchingProbe extends EconomicInvoiceDraftBatchingProbe
    {
        public int $failOnBatch = 1;

        protected function sendDraftLines(array $draft_lines): object
        {
            if (count($this->sentBatches) + 1 === $this->failOnBatch) {
                throw new RuntimeException('Simulated e-conomic line batch failure');
            }

            return parent::sendDraftLines($draft_lines);
        }
    }
}

it('does not call e-conomic when flushing an empty draft line buffer', function (): void {
    $draft = new EconomicInvoiceDraftBatchingProbe(123, 'DKK', true);

    $metrics = $draft->flushLinesInBatches();

    expect($metrics)->toBe([
        'line_count' => 0,
        'batch_count' => 0,
        'batch_sizes' => [],
    ])->and($draft->sentBatches)->toBe([]);
});

it('flushes a small draft line buffer in one request and clears pending lines', function (): void {
    $draft = new EconomicInvoiceDraftBatchingProbe(123, 'DKK', true);
    $draft->addTextLine('line-0');
    $draft->addTextLine('line-1');
    $draft->addTextLine('line-2');

    $metrics = $draft->flushLinesInBatches(500);

    expect($metrics)->toBe([
        'line_count' => 3,
        'batch_count' => 1,
        'batch_sizes' => [3],
    ])->and($draft->sentBatches)->toHaveCount(1)
        ->and($draft->sentBatches[0][0]['description'])->toBe('line-0')
        ->and($draft->sentBatches[0][2]['description'])->toBe('line-2')
        ->and($draft->pendingLineCount())->toBe(0);
});

it('chunks large draft line buffers while preserving line order', function (): void {
    $draft = new EconomicInvoiceDraftBatchingProbe(123, 'DKK', true);
    for ($i = 0; $i < 1201; $i++) {
        $draft->addTextLine('line-' . $i);
    }

    $metrics = $draft->flushLinesInBatches(500);

    expect($metrics)->toBe([
        'line_count' => 1201,
        'batch_count' => 3,
        'batch_sizes' => [500, 500, 201],
    ])->and($draft->sentBatches)->toHaveCount(3)
        ->and($draft->sentBatches[0][0]['description'])->toBe('line-0')
        ->and($draft->sentBatches[1][0]['description'])->toBe('line-500')
        ->and($draft->sentBatches[2][200]['description'])->toBe('line-1200')
        ->and($draft->pendingLineCount())->toBe(0);
});

it('bubbles line batch failures and keeps pending lines available', function (): void {
    $draft = new EconomicInvoiceDraftFailingBatchingProbe(123, 'DKK', true);
    $draft->addTextLine('line-0');

    expect(fn () => $draft->flushLinesInBatches(500))
        ->toThrow(RuntimeException::class, 'Simulated e-conomic line batch failure');

    expect($draft->sentBatches)->toBe([])
        ->and($draft->pendingLineCount())->toBe(1);
});
