<?php

declare(strict_types=1);

use Builder\Core\Foundation\Middleware\EnsureMfaIsComplete;
use Builder\Core\Tests\BuilderTestUser;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Schema;
use Symfony\Component\HttpFoundation\Response;

beforeEach(function (): void {
    Schema::create('users', function ($table): void {
        $table->id();
        $table->string('name')->nullable();
        $table->string('email')->nullable()->unique();
        $table->string('password')->nullable();
        $table->text('two_factor_secret')->nullable();
        $table->text('two_factor_recovery_codes')->nullable();
        $table->timestamp('two_factor_confirmed_at')->nullable();
        $table->rememberToken();
        $table->timestamps();
    });

    config(['auth.providers.users.model' => BuilderTestUser::class]);
});

it('passes through when user is not authenticated (no user)', function (): void {
    config(['builder.auth.require_mfa' => true]);

    $middleware = new EnsureMfaIsComplete;
    $request = Request::create('/');

    $called = false;
    $next = function ($req) use (&$called): Response {
        $called = true;

        return new Response('ok');
    };

    $response = $middleware->handle($request, $next);

    expect($called)->toBeTrue()
        ->and($response->getContent())->toBe('ok');
});

it('passes through when require_mfa is false (default)', function (): void {
    config(['builder.auth.require_mfa' => false]);

    $user = BuilderTestUser::create([
        'name' => 'Jane',
        'email' => 'jane@example.com',
        'password' => 'secret',
    ]);

    $this->actingAs($user)
        ->get(route('builder.dashboard'))
        ->assertOk();
});

it('redirects to account page when require_mfa is true and MFA not configured', function (): void {
    config(['builder.auth.require_mfa' => true]);

    $user = BuilderTestUser::create([
        'name' => 'Jane',
        'email' => 'jane@example.com',
        'password' => 'secret',
        'two_factor_confirmed_at' => null,
    ]);

    $this->actingAs($user)
        ->get(route('builder.dashboard'))
        ->assertRedirect(route('builder.account.show'));
});

it('redirects to mfa challenge when require_mfa is true and MFA not yet verified in session', function (): void {
    config(['builder.auth.require_mfa' => true]);

    $user = BuilderTestUser::create([
        'name' => 'Jane',
        'email' => 'jane@example.com',
        'password' => 'secret',
        'two_factor_confirmed_at' => now(),
    ]);

    $this->actingAs($user)
        ->get(route('builder.dashboard'))
        ->assertRedirect(route('builder.mfa.challenge'));
});

it('passes through when require_mfa is true and MFA is verified in session', function (): void {
    config(['builder.auth.require_mfa' => true]);

    $user = BuilderTestUser::create([
        'name' => 'Jane',
        'email' => 'jane@example.com',
        'password' => 'secret',
        'two_factor_confirmed_at' => now(),
    ]);

    $this->actingAs($user)
        ->withSession(['mfa_verified' => true])
        ->get(route('builder.dashboard'))
        ->assertOk();
});

it('exempt routes pass through even when require_mfa is true and MFA not verified', function (): void {
    config(['builder.auth.require_mfa' => true]);

    $user = BuilderTestUser::create([
        'name' => 'Jane',
        'email' => 'jane@example.com',
        'password' => 'secret',
        'two_factor_confirmed_at' => now(),
    ]);

    // Account page is exempt
    $this->actingAs($user)
        ->get(route('builder.account.show'))
        ->assertOk();
});
