<?php

declare(strict_types=1);

/**
 * LiveComponent Testing Example: CounterComponent
 *
 * Demonstrates usage of Pest helper functions for LiveComponent testing:
 * - mountComponent() - Mount component with initial state
 * - callAction() - Execute component actions
 * - callActionWithFragments() - Execute actions with fragment updates
 * - Custom Expectations: toHaveState, toContainHtml, toHaveDispatchedEvent
 */

use function Pest\LiveComponents\mountComponent;
use function Pest\LiveComponents\callAction;

describe('CounterComponent', function () {
    it('renders initial counter state', function () {
        $component = mountComponent('counter:test', ['count' => 0]);

        expect($component['html'])
            ->toContainHtml('Count: 0');

        expect($component['state'])
            ->toHaveState(['count' => 0, 'lastUpdate' => null]);
    });

    it('renders with custom initial count', function () {
        $component = mountComponent('counter:test', ['count' => 42]);

        expect($component['html'])
            ->toContainHtml('Count: 42');

        expect($component['state'])
            ->toHaveStateKey('count', 42);
    });

    it('increments counter on action', function () {
        $component = mountComponent('counter:test', ['count' => 5]);

        $result = callAction($component, 'increment');

        expect($result['state'])
            ->toHaveStateKey('count', 6);

        expect($result['html'])
            ->toContainHtml('Count: 6');
    });

    it('decrements counter on action', function () {
        $component = mountComponent('counter:test', ['count' => 5]);

        $result = callAction($component, 'decrement');

        expect($result['state'])
            ->toHaveStateKey('count', 4);

        expect($result['html'])
            ->toContainHtml('Count: 4');
    });

    it('prevents negative counts on decrement', function () {
        $component = mountComponent('counter:test', ['count' => 0]);

        $result = callAction($component, 'decrement');

        expect($result['state'])
            ->toHaveStateKey('count', 0); // Should stay at 0, not go negative
    });

    it('resets counter to zero', function () {
        $component = mountComponent('counter:test', ['count' => 42]);

        $result = callAction($component, 'reset');

        expect($result['state'])
            ->toHaveStateKey('count', 0);
    });

    it('adds custom amount to counter', function () {
        $component = mountComponent('counter:test', ['count' => 10]);

        $result = callAction($component, 'addAmount', ['amount' => 15]);

        expect($result['state'])
            ->toHaveStateKey('count', 25);
    });

    it('prevents negative counts when adding negative amount', function () {
        $component = mountComponent('counter:test', ['count' => 5]);

        $result = callAction($component, 'addAmount', ['amount' => -10]);

        expect($result['state'])
            ->toHaveStateKey('count', 0); // Should be capped at 0
    });

    it('dispatches counter:changed event on increment', function () {
        $component = mountComponent('counter:test', ['count' => 5]);

        $result = callAction($component, 'increment');

        expect($result['events'])
            ->toHaveDispatchedEvent('counter:changed');
    });

    it('dispatches counter:changed event with correct data', function () {
        $component = mountComponent('counter:test', ['count' => 5]);

        $result = callAction($component, 'increment');

        expect($result['events'])
            ->toHaveDispatchedEventWithData('counter:changed', [
                'component_id' => 'counter:test',
                'old_value' => 5,
                'new_value' => 6,
                'change' => '+1',
            ]);
    });

    it('dispatches milestone event at multiples of 10', function () {
        $component = mountComponent('counter:test', ['count' => 9]);

        $result = callAction($component, 'increment');

        expect($result['events'])
            ->toHaveDispatchedEvent('counter:milestone');
    });

    it('does not dispatch milestone event when not at multiple of 10', function () {
        $component = mountComponent('counter:test', ['count' => 8]);

        $result = callAction($component, 'increment');

        // Should have counter:changed but not milestone
        expect($result['events'])->toHaveDispatchedEvent('counter:changed');

        $hasMilestone = false;
        foreach ($result['events'] as $event) {
            if ($event->name === 'counter:milestone') {
                $hasMilestone = true;
            }
        }

        expect($hasMilestone)->toBeFalse();
    });

    it('dispatches reset event on reset action', function () {
        $component = mountComponent('counter:test', ['count' => 42]);

        $result = callAction($component, 'reset');

        expect($result['events'])
            ->toHaveDispatchedEventWithData('counter:reset', [
                'component_id' => 'counter:test',
                'previous_value' => 42,
            ]);
    });

    it('maintains component identity across actions', function () {
        $component = mountComponent('counter:test');

        $result1 = callAction($component, 'increment');
        $result2 = callAction($result1, 'increment');

        expect($result2['componentId'])->toBe('counter:test');
        expect($result2['state']['count'])->toBe(2);
    });

    it('chains multiple actions correctly', function () {
        $component = mountComponent('counter:test', ['count' => 0]);

        $result = callAction($component, 'increment');
        $result = callAction($result, 'increment');
        $result = callAction($result, 'increment');
        $result = callAction($result, 'decrement');

        expect($result['state']['count'])->toBe(2);
    });
});
