<?php

namespace Statamic\Http\Controllers;

use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Inertia\Inertia;
use Statamic\Events\TwoFactorAuthenticationFailed;
use Statamic\Events\ValidTwoFactorAuthenticationCodeProvided;
use Statamic\Facades\URL;
use Statamic\Http\Middleware\CP\HandleInertiaRequests;
use Statamic\Http\Middleware\RedirectIfAuthenticated;
use Statamic\Http\Requests\TwoFactorChallengeRequest;

class TwoFactorChallengeController extends Controller
{
    public function __construct(Request $request)
    {
        $this->middleware('throttle:two-factor');
        $this->middleware(HandleInertiaRequests::class);
        $this->middleware(RedirectIfAuthenticated::class);
    }

    public function index(TwoFactorChallengeRequest $request)
    {
        if (! $request->hasChallengedUser()) {
            throw new HttpResponseException(redirect()->route('statamic.cp.login'));
        }

        return Inertia::render('auth/two-factor/Challenge', [
            'action' => $this->formAction(),
            'mode' => session()->get('errors')?->getBag('default')->has('recovery_code') ? 'recovery_code' : 'code',
            'csrfToken' => csrf_token(),
            'redirect' => $request->redirect,
        ]);
    }

    public function store(TwoFactorChallengeRequest $request)
    {
        $user = $request->challengedUser();

        if ($code = $request->validRecoveryCode()) {
            $user->replaceTwoFactorRecoveryCode($code);
        } elseif (! $request->hasValidCode()) {
            TwoFactorAuthenticationFailed::dispatch($user);

            return $request->sendFailedTwoFactorChallengeResponse();
        }

        ValidTwoFactorAuthenticationCodeProvided::dispatch($user);

        Auth::guard()->login($user, $request->remember());

        $request->session()->elevate();

        $request->session()->regenerate();

        return $request->expectsJson()
            ? response('Authenticated')
            : redirect()->intended($this->redirectPath());
    }

    protected function formAction()
    {
        return route('statamic.two-factor-challenge');
    }

    protected function redirectPath()
    {
        $redirect = request('redirect');

        return $redirect && ! URL::isExternalToApplication($redirect)
            ? $redirect
            : route('statamic.site');
    }
}
