<?php
/*
 * Copyright 2026 Alessandro Chiapparini <sprint_planer_web@chiapparini.org>
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * See the LICENSE file in the project root for the full license text.
 */

declare(strict_types=1);

namespace App\Tests\Auth;

use App\Auth\BootstrapAdmin;
use App\Tests\TestCase;

/**
 * Lock-in tests for R01-N03 — the OIDC bootstrap matcher. The matcher
 * is the only thing standing between an unconfigured deploy and the
 * historical "first user wins" land-grab.
 */
final class BootstrapAdminTest extends TestCase
{
    /** @var array<string, string|false> */
    private array $envBackup = [];

    /** @var string[] */
    private array $envKeys = [
        'BOOTSTRAP_ADMIN_OID',
        'BOOTSTRAP_ADMIN_EMAIL',
    ];

    protected function setUp(): void
    {
        parent::setUp();
        foreach ($this->envKeys as $k) {
            $this->envBackup[$k] = getenv($k);
            putenv($k);
        }
    }

    protected function tearDown(): void
    {
        foreach ($this->envKeys as $k) {
            $prev = $this->envBackup[$k] ?? false;
            if ($prev === false) {
                putenv($k);
            } else {
                putenv("{$k}={$prev}");
            }
        }
        parent::tearDown();
    }

    public function testNotConfiguredByDefault(): void
    {
        self::assertFalse(BootstrapAdmin::isConfigured());
        self::assertFalse(
            BootstrapAdmin::matches('any-oid', 'any@example.com'),
            'unconfigured matcher must never promote anyone'
        );
    }

    public function testMatchesByOid(): void
    {
        putenv('BOOTSTRAP_ADMIN_OID=00000000-0000-0000-0000-000000000001');
        self::assertTrue(BootstrapAdmin::isConfigured());
        self::assertTrue(BootstrapAdmin::matches(
            '00000000-0000-0000-0000-000000000001',
            'unrelated@example.com'
        ));
        self::assertFalse(BootstrapAdmin::matches(
            '00000000-0000-0000-0000-000000000002',
            'unrelated@example.com'
        ));
    }

    public function testMatchesByEmail(): void
    {
        putenv('BOOTSTRAP_ADMIN_EMAIL=admin@example.com');
        self::assertTrue(BootstrapAdmin::isConfigured());
        self::assertTrue(BootstrapAdmin::matches(
            'oid-does-not-matter',
            'admin@example.com'
        ));
        self::assertFalse(BootstrapAdmin::matches(
            'oid-does-not-matter',
            'attacker@example.com'
        ));
    }

    public function testEitherChannelMatchesWhenBothConfigured(): void
    {
        putenv('BOOTSTRAP_ADMIN_OID=oid-1');
        putenv('BOOTSTRAP_ADMIN_EMAIL=admin@example.com');

        self::assertTrue(BootstrapAdmin::matches('oid-1',  'someone-else@x'));
        self::assertTrue(BootstrapAdmin::matches('oid-99', 'admin@example.com'));
        self::assertFalse(BootstrapAdmin::matches('oid-99', 'someone-else@x'));
    }

    public function testMatchIsCaseInsensitiveAndTrimmed(): void
    {
        putenv('BOOTSTRAP_ADMIN_EMAIL=Admin@Example.COM');
        self::assertTrue(BootstrapAdmin::matches('', '  admin@example.com  '));

        putenv('BOOTSTRAP_ADMIN_EMAIL');
        putenv('BOOTSTRAP_ADMIN_OID=ABCDEF-1234');
        self::assertTrue(BootstrapAdmin::matches('  abcdef-1234  ', ''));
    }

    public function testBlankIncomingFieldsNeverMatch(): void
    {
        // Blank email in env shouldn't match a blank claim — config is
        // OID-only here, so an empty email coming back from Entra must
        // not opportunistically match the absent BOOTSTRAP_ADMIN_EMAIL.
        putenv('BOOTSTRAP_ADMIN_OID=oid-1');
        self::assertFalse(BootstrapAdmin::matches('', ''));
        self::assertFalse(BootstrapAdmin::matches('', 'bob@x'));
    }

    public function testWhitespaceOnlyEnvTreatedAsUnset(): void
    {
        putenv('BOOTSTRAP_ADMIN_OID=   ');
        putenv('BOOTSTRAP_ADMIN_EMAIL=   ');
        self::assertFalse(BootstrapAdmin::isConfigured());
        self::assertFalse(BootstrapAdmin::matches('anything', 'anything@x'));
    }

    public function testOidValueOverEmailIsPreferred(): void
    {
        // Both are set; if the user's oid matches we promote regardless of
        // a (presumably stale) BOOTSTRAP_ADMIN_EMAIL. Sanity check that
        // either-channel-wins still holds.
        putenv('BOOTSTRAP_ADMIN_OID=primary-oid');
        putenv('BOOTSTRAP_ADMIN_EMAIL=admin@example.com');
        self::assertTrue(BootstrapAdmin::matches('primary-oid', 'noone@x'));
    }
}
