<?php



namespace App\Http\Controllers\Admin;



use App\Http\Controllers\Controller;

use App\Support\ActivityLogger;

use Illuminate\Http\RedirectResponse;

use Illuminate\Http\Request;

use Illuminate\Support\Facades\Hash;

use Illuminate\View\View;

use PragmaRX\Google2FA\Google2FA;



class TwoFactorSecurityController extends Controller

{

    private const SETUP_SESSION_KEY = 'two_factor_setup';



    public function show(Request $request): View

    {

        $this->forgetStaleSetup($request);



        $setup = $request->session()->get(self::SETUP_SESSION_KEY);

        $setupSecret = is_array($setup) ? ($setup['secret'] ?? null) : null;

        $qrUrl = null;

        if ($setupSecret && $request->user()) {

            $google2fa = new Google2FA;

            $qrUrl = $google2fa->getQRCodeUrl(

                config('app.name', 'News'),

                $request->user()->email,

                $setupSecret

            );

        }



        return view('admin.security.two-factor', [

            'enabled' => $request->user()->hasTwoFactorEnabled(),

            'setupSecret' => $setupSecret,

            'qrUrl' => $qrUrl,

        ]);

    }



    public function begin(Request $request): RedirectResponse

    {

        if (! $request->user()->is_admin) {

            abort(403);

        }



        if ($request->user()->hasTwoFactorEnabled()) {

            return redirect()->route('admin.security.two-factor');

        }



        $google2fa = new Google2FA;

        $secret = $google2fa->generateSecretKey();

        $request->session()->put(self::SETUP_SESSION_KEY, [

            'secret' => $secret,

            'at' => now()->timestamp,

        ]);



        return redirect()->route('admin.security.two-factor')

            ->with('success', __('Scan the QR code or enter the secret, then confirm with a code.'));

    }



    public function confirm(Request $request): RedirectResponse

    {

        if (! $request->user()->is_admin) {

            abort(403);

        }



        $request->validate([

            'code' => ['required', 'string', 'regex:/^\d{6}$/'],

        ]);



        $setup = $request->session()->get(self::SETUP_SESSION_KEY);

        $secret = is_array($setup) ? ($setup['secret'] ?? null) : null;

        if (! $secret) {

            return redirect()->route('admin.security.two-factor')

                ->with('error', __('Please start setup again.'));

        }



        $google2fa = new Google2FA;

        if (! $google2fa->verifyKey($secret, preg_replace('/\s+/', '', $request->code), 4)) {

            return redirect()->route('admin.security.two-factor')

                ->with('error', __('The code is invalid. Try again.'))

                ->withInput();

        }



        $request->user()->forceFill([

            'two_factor_secret' => $secret,

            'two_factor_confirmed_at' => now(),

        ])->save();



        $request->session()->forget(self::SETUP_SESSION_KEY);



        ActivityLogger::log('two_factor.enabled', __('Two-factor authentication enabled'), $request->user());



        return redirect()->route('admin.security.two-factor')

            ->with('success', __('Two-factor authentication is now active.'));

    }



    public function disable(Request $request): RedirectResponse

    {

        if (! $request->user()->is_admin) {

            abort(403);

        }



        $request->validate([

            'password' => 'required|string',

        ]);



        if (! Hash::check($request->password, $request->user()->password)) {

            return redirect()->route('admin.security.two-factor')

                ->with('error', __('Incorrect password.'));

        }



        $request->user()->forceFill([

            'two_factor_secret' => null,

            'two_factor_confirmed_at' => null,

        ])->save();



        $request->session()->forget(self::SETUP_SESSION_KEY);



        ActivityLogger::log('two_factor.disabled', __('Two-factor authentication disabled'), $request->user());



        return redirect()->route('admin.security.two-factor')

            ->with('success', __('Two-factor authentication has been turned off.'));

    }



    private function forgetStaleSetup(Request $request): void

    {

        $setup = $request->session()->get(self::SETUP_SESSION_KEY);

        if (! is_array($setup) || empty($setup['at'])) {

            return;

        }

        if (now()->timestamp - (int) $setup['at'] > 900) {

            $request->session()->forget(self::SETUP_SESSION_KEY);

        }

    }

}

