<?php

declare(strict_types=1);

namespace Builder\Core\Http\Controllers\Auth;

use Builder\Core\Http\Requests\Auth\VerifyMfaRequest;
use Illuminate\Http\RedirectResponse;
use PragmaRX\Google2FA\Google2FA;

final class StoreMfaChallengeController
{
    private const string SESSION_MFA_VERIFIED = 'mfa_verified';

    public function __invoke(VerifyMfaRequest $request): RedirectResponse
    {
        $user = $request->user();
        assert($user !== null);
        $code = $request->string('code')->toString();

        if ($user->getAttribute('two_factor_secret') !== null) {
            $secret = decrypt((string) $user->getAttribute('two_factor_secret'));
            $google2fa = new Google2FA;

            if ($google2fa->verifyKey($secret, $code)) {
                $request->session()->put(self::SESSION_MFA_VERIFIED, true);

                return to_route('builder.dashboard');
            }
        }

        if ($user->getAttribute('two_factor_recovery_codes') !== null) {
            $recoveryCodes = json_decode((string) decrypt((string) $user->getAttribute('two_factor_recovery_codes')), true);

            if (is_array($recoveryCodes) && in_array(strtoupper($code), array_map('strtoupper', $recoveryCodes), true)) {
                $remaining = array_values(array_filter(
                    $recoveryCodes,
                    fn (string $c): bool => strtoupper($c) !== strtoupper($code),
                ));

                $user->forceFill([
                    'two_factor_recovery_codes' => encrypt(json_encode($remaining)),
                ])->save();

                $request->session()->put(self::SESSION_MFA_VERIFIED, true);

                return to_route('builder.dashboard');
            }
        }

        return back()->withErrors(['code' => 'Invalid code. Please try again.']);
    }
}
