<?php

use App\Models\User;

// operator()/admin() helpers live in tests/Pest.php.

it('serves the console on any host when ADMIN_HOSTS is empty (default)', function () {
    config()->set('admin_access.hosts', []);

    $this->actingAs(operator('Owner'), 'operator')
        ->get('http://app.dev.clupilot.com/admin')
        ->assertOk();
});

it('404s the console on a hostname that is not allowed', function () {
    config()->set('admin_access.hosts', ['admin.dev.clupilot.com']);

    // A PUBLIC hostname must not even hint that a console exists here.
    $this->actingAs(operator('Owner'), 'operator')
        ->get('http://app.dev.clupilot.com/admin')
        ->assertNotFound();

    $this->actingAs(operator('Owner'), 'operator')
        ->get('http://www.dev.clupilot.com/admin/hosts')
        ->assertNotFound();
});

it('serves the console on an allowed hostname', function () {
    config()->set('admin_access.hosts', ['admin.dev.clupilot.com', '10.10.90.185']);

    $this->actingAs(operator('Owner'), 'operator')
        ->get('http://admin.dev.clupilot.com/admin')
        ->assertOk();

    $this->actingAs(operator('Owner'), 'operator')
        ->get('http://10.10.90.185/admin')
        ->assertOk();
});

it('matches configured hostnames case-insensitively', function () {
    // DNS is case-insensitive and getHost() lowercases, so ADMIN_HOSTS with any
    // capitals must still match — otherwise a typo silently locks operators out.
    config()->set('admin_access.hosts', ['Admin.Dev.CluPilot.COM']);

    $this->actingAs(operator('Owner'), 'operator')
        ->get('http://admin.dev.clupilot.com/admin')
        ->assertOk();

    // …and the restriction still bites on everything else.
    $this->actingAs(operator('Owner'), 'operator')
        ->get('http://www.dev.clupilot.com/admin')
        ->assertNotFound();
});

it('404s before revealing a login redirect to guests on a public host', function () {
    config()->set('admin_access.hosts', ['admin.dev.clupilot.com']);

    // Not a redirect to /login — that would confirm the console's existence.
    $this->get('http://www.dev.clupilot.com/admin')->assertNotFound();
});

it('blocks admin Livewire actions posted through a public hostname', function () {
    // Admin actions go to /livewire/update, which a path-based guard would skip.
    // Livewire must re-apply the host restriction from the component's route.
    config()->set('admin_access.hosts', ['admin.dev.clupilot.com']);
    $owner = operator('Owner');

    // Render the real page on an ALLOWED host so Livewire records the admin
    // route's middleware on the snapshot (Livewire::test() skips HTTP routing
    // and would not, which would make this test pass for the wrong reason).
    $html = $this->actingAs($owner, 'operator')
        ->get('http://admin.dev.clupilot.com/admin/datacenters')
        ->assertOk()
        ->getContent();

    expect($html)->toMatch('/wire:snapshot=/');
    preg_match('/wire:snapshot="([^"]+)"/', $html, $m);
    $snapshot = html_entity_decode($m[1], ENT_QUOTES);

    $payload = fn () => [
        '_token' => csrf_token(),
        'components' => [[
            'snapshot' => $snapshot,
            'updates' => [],
            'calls' => [['path' => '', 'method' => 'save', 'params' => []]],
        ]],
    ];

    // Replayed against a PUBLIC hostname → must not execute.
    $this->actingAs($owner, 'operator')
        ->post('http://www.dev.clupilot.com/livewire/update', $payload())
        ->assertNotFound();

    // Positive control: the very same payload works on the allowed host, so the
    // 404 above is the restriction — not a malformed request.
    $this->actingAs($owner, 'operator')
        ->post('http://admin.dev.clupilot.com/livewire/update', $payload())
        ->assertOk();
});

it('registers the host restriction as Livewire-persistent middleware', function () {
    // Guards the wiring above: without this, /livewire/update bypasses ADMIN_HOSTS.
    $persistent = (new ReflectionClass(\Livewire\Mechanisms\PersistentMiddleware\PersistentMiddleware::class))
        ->getProperty('persistentMiddleware');

    expect($persistent->getValue(app(\Livewire\Mechanisms\PersistentMiddleware\PersistentMiddleware::class)))
        ->toContain(\App\Http\Middleware\RestrictAdminHost::class);
});

it('keeps the customer portal reachable on public hosts', function () {
    config()->set('admin_access.hosts', ['admin.dev.clupilot.com']);
    $user = User::factory()->create();

    $this->actingAs($user)->get('http://app.dev.clupilot.com/dashboard')->assertOk();
    $this->get('http://www.dev.clupilot.com/')->assertOk();
});
