<?php

declare(strict_types=1);

use App\Services\Hook\HookManager;

/**
 * Hook 시스템 Pest 테스트 — 그누보드 g7 Action/Filter 패리티 검증.
 */

beforeEach(function () {
    $this->hook = new HookManager;
});

it('invokes registered actions with arguments', function () {
    $received = [];

    $this->hook->addAction('core.user.after_create', function (string $userId) use (&$received) {
        $received[] = $userId;
    });

    $this->hook->doAction('core.user.after_create', 'user-abc-123');

    expect($received)->toBe(['user-abc-123']);
});

it('transforms values via filter chain in priority order', function () {
    $this->hook->addFilter('core.user.filter_create_data', fn (array $data) => array_merge($data, ['stage' => 'lower']), 20);
    $this->hook->addFilter('core.user.filter_create_data', fn (array $data) => array_merge($data, ['stage' => 'higher']), 10);

    $result = $this->hook->applyFilters('core.user.filter_create_data', ['name' => 'kim']);

    // priority 10 먼저, 20 이 나중 — 최종 stage 는 'lower' 여야 함
    expect($result)->toMatchArray([
        'name' => 'kim',
        'stage' => 'lower',
    ]);
});

it('respects action priority order', function () {
    $order = [];

    $this->hook->addAction('test.order', fn () => $order[] = 'late', 99);
    $this->hook->addAction('test.order', fn () => $order[] = 'early', 1);
    $this->hook->addAction('test.order', fn () => $order[] = 'mid', 50);

    $this->hook->doAction('test.order');

    expect($order)->toBe(['early', 'mid', 'late']);
});

it('returns value unchanged when no filters registered', function () {
    $result = $this->hook->applyFilters('unknown.filter', 'pristine');
    expect($result)->toBe('pristine');
});

it('silently ignores doAction for unregistered events', function () {
    expect(fn () => $this->hook->doAction('unknown.event', 'x'))->not->toThrow(\Throwable::class);
});

it('lists registered event names', function () {
    $this->hook->addAction('a.one', fn () => null);
    $this->hook->addFilter('a.filter_two', fn ($v) => $v);

    $events = $this->hook->listEvents();

    expect($events['actions'])->toContain('a.one');
    expect($events['filters'])->toContain('a.filter_two');
});
