<?php

use Illuminate\Support\Facades\Blade;

/**
 * An icon sits BESIDE its label, at the size the call site asked for.
 *
 * Both halves of that sentence were broken at once in the console sidebar: the
 * "Zugangsdaten" entry rendered the lock above the word instead of next to it,
 * and at 20px instead of the 16px it was written as. The two causes are
 * independent, so they are tested independently.
 */

it('renders an icon at the size the call site asked for', function () {
    // Not a style preference: `.size-4` and `.size-5` have the same
    // specificity, so the one Tailwind emits LATER wins — and it emits size-4
    // first. A component that always merges its own size therefore overrides
    // every caller that picked a smaller one.
    $html = Blade::render('<x-ui.icon name="lock" class="size-4" />');

    expect($html)->toContain('size-4')->not->toContain('size-5');
});

it('falls back to its own size when the call site names none', function () {
    expect(Blade::render('<x-ui.icon name="lock" />'))->toContain('size-5');
});

it('keeps an icon on the line it was written on', function () {
    // Tailwind's preflight makes every svg display:block. Inside an inline
    // parent that pushes the following text onto a second line, which is how a
    // one-line navigation entry became two lines tall.
    expect(Blade::render('<x-ui.icon name="lock" />'))
        ->toContain('inline-block')
        ->toContain('shrink-0');
});

it('keeps a navigation entry on one line whichever slot the icon uses', function () {
    // Blade::render leaves a slot's output buffer open when a component is
    // rendered outside a request, which PHPUnit reports as a risky test. The
    // markup it returns is complete; only the buffer needs tidying.
    $render = function (string $template): string {
        $level = ob_get_level();

        try {
            return Blade::render($template);
        } finally {
            while (ob_get_level() > $level) {
                ob_end_clean();
            }
        }
    };

    $viaSlot = $render(
        '<x-ui.nav-item href="/x"><x-slot:icon><x-ui.icon name="lock" /></x-slot:icon>Zugangsdaten</x-ui.nav-item>'
    );

    // The mistake that caused the report: the icon handed to the DEFAULT slot
    // rather than the icon slot. The layout must not depend on which was used.
    $viaDefaultSlot = $render(
        '<x-ui.nav-item href="/x"><x-ui.icon name="lock" />Zugangsdaten</x-ui.nav-item>'
    );

    foreach ([$viaSlot, $viaDefaultSlot] as $html) {
        expect($html)
            ->toContain('items-center')
            ->toContain('Zugangsdaten')
            // The label wrapper is a flex row of its own, so a stray icon lands
            // next to the text rather than above it.
            ->toContain('flex min-w-0 items-center gap-3');
    }
});

it('puts navigation icons in the icon slot everywhere', function () {
    // Belt to the component's braces. The component now survives an icon in the
    // wrong slot, but the wrong slot also skips the shrink-0 wrapper and reads
    // as an accident to the next person editing the file.
    $offenders = [];

    $files = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator(resource_path('views'), FilesystemIterator::SKIP_DOTS)
    );

    foreach ($files as $file) {
        if (! str_ends_with($file->getFilename(), '.blade.php')) {
            continue;
        }

        $source = (string) file_get_contents($file->getPathname());

        // Each nav-item element, from its opening tag to its closing one.
        preg_match_all('/<x-ui\.nav-item\b.*?<\/x-ui\.nav-item>/s', $source, $matches);

        foreach ($matches[0] as $element) {
            $withoutIconSlot = preg_replace('/<x-slot:icon>.*?<\/x-slot:icon>/s', '', $element);

            if (str_contains((string) $withoutIconSlot, '<x-ui.icon')) {
                $offenders[] = str_replace(resource_path('views').'/', '', $file->getPathname());
            }
        }
    }

    expect($offenders)->toBe([]);
});
