<?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\OidcClient;
use App\Tests\TestCase;

/**
 * Pins the OIDC env-driven gating: `isConfigured()` is true only when every
 * ENTRA_* + APP_BASE_URL var is set AND `OIDC_ENABLED` isn't explicitly false.
 * The `OIDC_ENABLED=false` path is the dev/testing kill-switch that lets
 * operators run on the LOCAL_ADMIN_* fallback alone without unsetting the
 * Entra creds in .env.
 */
final class OidcClientTest extends TestCase
{
    /** @var array<string, string|false> */
    private array $envBackup = [];

    /** @var string[] */
    private array $envKeys = [
        'ENTRA_TENANT_ID',
        'ENTRA_CLIENT_ID',
        'ENTRA_CLIENT_SECRET',
        'APP_BASE_URL',
        'OIDC_ENABLED',
    ];

    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();
    }

    private function setEntraVars(): void
    {
        putenv('ENTRA_TENANT_ID=tenant-guid');
        putenv('ENTRA_CLIENT_ID=client-guid');
        putenv('ENTRA_CLIENT_SECRET=secret');
        putenv('APP_BASE_URL=https://example.com');
    }

    public function testNotConfiguredWithoutEntraVars(): void
    {
        self::assertFalse(OidcClient::isConfigured());
        self::assertFalse(OidcClient::isExplicitlyDisabled());
    }

    public function testConfiguredWhenAllEntraVarsSet(): void
    {
        $this->setEntraVars();
        self::assertTrue(OidcClient::isConfigured());
        self::assertFalse(OidcClient::isExplicitlyDisabled());
    }

    public function testConfiguredStaysTrueWhenFlagBlankOrUnset(): void
    {
        $this->setEntraVars();
        // Unset (default of putenv with no =).
        putenv('OIDC_ENABLED');
        self::assertTrue(OidcClient::isConfigured());
        // Explicit blank.
        putenv('OIDC_ENABLED=');
        self::assertTrue(OidcClient::isConfigured());
        self::assertFalse(OidcClient::isExplicitlyDisabled());
    }

    public function testConfiguredStaysTrueWhenFlagAnyTruthyValue(): void
    {
        $this->setEntraVars();
        foreach (['true', '1', 'yes', 'on', 'TRUE', 'enabled', 'whatever'] as $v) {
            putenv("OIDC_ENABLED={$v}");
            self::assertTrue(
                OidcClient::isConfigured(),
                "isConfigured() should be true with OIDC_ENABLED={$v}",
            );
            self::assertFalse(
                OidcClient::isExplicitlyDisabled(),
                "isExplicitlyDisabled() should be false with OIDC_ENABLED={$v}",
            );
        }
    }

    public function testFalseyFlagDisablesOidcEvenWithEntraVarsSet(): void
    {
        $this->setEntraVars();
        foreach (['false', '0', 'no', 'off', 'FALSE', 'No', ' off '] as $v) {
            putenv("OIDC_ENABLED={$v}");
            self::assertFalse(
                OidcClient::isConfigured(),
                "isConfigured() should be false with OIDC_ENABLED={$v}",
            );
            self::assertTrue(
                OidcClient::isExplicitlyDisabled(),
                "isExplicitlyDisabled() should be true with OIDC_ENABLED={$v}",
            );
        }
    }

    public function testFalseyFlagWithoutEntraVarsStillReportsDisabled(): void
    {
        // No ENTRA_*. Flag set false. isConfigured stays false (already was);
        // isExplicitlyDisabled tells the operator-facing page which message
        // to show ("disabled" vs. "not configured").
        putenv('OIDC_ENABLED=false');
        self::assertFalse(OidcClient::isConfigured());
        self::assertTrue(OidcClient::isExplicitlyDisabled());
    }
}
