<?php

declare(strict_types=1);

use App\Support\Diff\DiffPresenter;
use App\Support\Diff\DiffRowStatus;

it('classifies rows across all shared states and derives matching summary counts', function (): void {
    $presentation = app(DiffPresenter::class)->present(
        baseline: [
            'description' => 'Before',
            'display_name' => 'TenantPilot',
            'retired_setting' => 'Legacy',
        ],
        current: [
            'description' => 'After',
            'display_name' => 'TenantPilot',
            'new_setting' => 'Enabled',
        ],
        labels: [
            'description' => 'Description',
            'display_name' => 'Display name',
            'new_setting' => 'New setting',
            'retired_setting' => 'Retired setting',
        ],
    );

    $rows = collect($presentation->rows)->keyBy('key');

    expect($presentation->summary->changedCount)->toBe(1)
        ->and($presentation->summary->addedCount)->toBe(1)
        ->and($presentation->summary->removedCount)->toBe(1)
        ->and($presentation->summary->unchangedCount)->toBe(1)
        ->and($presentation->summary->hasRows)->toBeTrue()
        ->and($rows->get('description')?->status)->toBe(DiffRowStatus::Changed)
        ->and($rows->get('display_name')?->status)->toBe(DiffRowStatus::Unchanged)
        ->and($rows->get('new_setting')?->status)->toBe(DiffRowStatus::Added)
        ->and($rows->get('retired_setting')?->status)->toBe(DiffRowStatus::Removed);
});

it('returns rows in deterministic label order', function (): void {
    $presentation = app(DiffPresenter::class)->present(
        baseline: [
            'zeta_value' => 'same',
            'alpha_value' => 'before',
        ],
        current: [
            'alpha_value' => 'after',
            'middle_value' => 'new',
            'zeta_value' => 'same',
        ],
        labels: [
            'alpha_value' => 'Alpha value',
            'middle_value' => 'Middle value',
            'zeta_value' => 'Zeta value',
        ],
    );

    expect(array_map(
        static fn ($row): string => $row->label,
        $presentation->rows,
    ))->toBe([
        'Alpha value',
        'Middle value',
        'Zeta value',
    ]);
});

it('prepares inline list fragments for simple list comparisons', function (): void {
    $presentation = app(DiffPresenter::class)->present(
        baseline: [
            'scope_tags' => ['Default', 'Legacy', 'Shared'],
        ],
        current: [
            'scope_tags' => ['Default', 'Shared', 'Workspace'],
        ],
        labels: [
            'scope_tags' => 'Scope tags',
        ],
    );

    $row = $presentation->rows[0] ?? null;

    expect($row)->not->toBeNull()
        ->and($row?->isListLike)->toBeTrue()
        ->and($row?->addedItems)->toBe(['Workspace'])
        ->and($row?->removedItems)->toBe(['Legacy'])
        ->and($row?->unchangedItems)->toBe(['Default', 'Shared']);
});

it('falls back to generated labels and safe empty meta when optional metadata is missing or invalid', function (): void {
    $presentation = app(DiffPresenter::class)->present(
        baseline: [
            'customSettingFoo' => 'Before',
        ],
        current: [
            'customSettingFoo' => 'After',
        ],
        meta: [
            'customSettingFoo' => 'invalid-meta-shape',
        ],
    );

    $row = $presentation->rows[0] ?? null;

    expect($row)->not->toBeNull()
        ->and($row?->label)->toBe('Custom Setting Foo')
        ->and($row?->meta)->toBe([]);
});

it('returns a no-data presentation for empty or sparse compare payloads', function (): void {
    $presentation = app(DiffPresenter::class)->present(
        baseline: [],
        current: [],
        changedKeys: ['ghost_key'],
        labels: ['ghost_key' => 'Ghost key'],
        meta: ['ghost_key' => ['note' => 'unused']],
    );

    expect($presentation->rows)->toBe([])
        ->and($presentation->summary->hasRows)->toBeFalse()
        ->and($presentation->summary->changedCount)->toBe(0)
        ->and($presentation->summary->addedCount)->toBe(0)
        ->and($presentation->summary->removedCount)->toBe(0)
        ->and($presentation->summary->unchangedCount)->toBe(0)
        ->and($presentation->summary->message)->toBe('No diff data available.');
});
