<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Inertia\Inertia;
use Inertia\Response;
use PragmaRX\Google2FA\Google2FA;

class TwoFactorController extends Controller
{
    public function __construct(private readonly Google2FA $google2fa) {}

    /**
     * Login-time challenge — shown after a successful password/Discord
     * login for accounts that already have 2FA confirmed.
     */
    public function create(): Response
    {
        return Inertia::render('Auth/TwoFactorChallenge');
    }

    public function store(Request $request): RedirectResponse
    {
        $request->validate(['code' => ['required', 'string']]);

        $user = $request->user();
        $throttleKey = 'two-factor:'.$user->id;

        if (RateLimiter::tooManyAttempts($throttleKey, 5)) {
            throw ValidationException::withMessages([
                'code' => 'Too many attempts. Please wait a minute before trying again.',
            ]);
        }

        $secret = Crypt::decryptString($user->two_factor_secret);
        $valid = $this->google2fa->verifyKey($secret, $request->string('code')->trim()->value());

        if (! $valid) {
            RateLimiter::hit($throttleKey, 60);

            throw ValidationException::withMessages(['code' => 'The provided code is invalid.']);
        }

        RateLimiter::clear($throttleKey);
        $request->session()->put('google2fa_authenticated', true);

        return redirect()->intended(route('dashboard'));
    }

    /**
     * Setup screen — generates (but does not yet activate) a new secret.
     */
    public function setup(Request $request): Response
    {
        $user = $request->user();

        if ($user->two_factor_confirmed_at !== null) {
            return Inertia::render('Auth/TwoFactorSetup', ['alreadyEnabled' => true]);
        }

        $secret = $this->google2fa->generateSecretKey();
        $request->session()->put('pending_two_factor_secret', $secret);

        return Inertia::render('Auth/TwoFactorSetup', [
            'alreadyEnabled' => false,
            'qrCodeUrl' => $this->google2fa->getQRCodeUrl(
                config('app.name'),
                $user->email,
                $secret,
            ),
            'secret' => $secret,
        ]);
    }

    public function confirm(Request $request): RedirectResponse
    {
        $request->validate(['code' => ['required', 'string']]);

        $secret = $request->session()->get('pending_two_factor_secret');

        if (! $secret) {
            return redirect()->route('two-factor.setup')->with('error', 'Your setup session expired, please try again.');
        }

        if (! $this->google2fa->verifyKey($secret, $request->string('code')->trim()->value())) {
            throw ValidationException::withMessages(['code' => 'The provided code is invalid.']);
        }

        $user = $request->user();
        $user->two_factor_secret = Crypt::encryptString($secret);
        $user->two_factor_recovery_codes = Crypt::encryptString(json_encode(
            collect()->times(8, fn () => Str::random(10).'-'.Str::random(10))->all()
        ));
        $user->two_factor_confirmed_at = now();
        $user->save();

        $request->session()->forget('pending_two_factor_secret');
        $request->session()->put('google2fa_authenticated', true);

        return redirect()->route('profile.edit')->with('success', 'Two-factor authentication has been enabled.');
    }

    public function disable(Request $request): RedirectResponse
    {
        $user = $request->user();
        $user->two_factor_secret = null;
        $user->two_factor_recovery_codes = null;
        $user->two_factor_confirmed_at = null;
        $user->save();

        $request->session()->forget('google2fa_authenticated');

        return redirect()->route('profile.edit')->with('success', 'Two-factor authentication has been disabled.');
    }
}
