<?php
namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Support\ApiResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Crypt;
use PragmaRX\Google2FA\Google2FA;

final class TwoFactorController extends Controller
{
    public function setup(Request $request, Google2FA $google2fa)
    {
        $secret = $google2fa->generateSecretKey();
        $cipher = Crypt::encryptString($secret);
        Cache::put($this->pendingSecretKey($request), $cipher, now()->addMinutes(10));

        if ($request->hasSession()) {
            $request->session()->put('pending_2fa_secret', $cipher);
        }

        return ApiResponse::success([
            'secret' => $secret,
            'otpauth_url' => $google2fa->getQRCodeUrl(config('app.name'), $request->user()->email, $secret),
        ]);
    }

    public function enable(Request $request, Google2FA $google2fa)
    {
        $data = $request->validate(['code' => ['required','digits:6']]);
        $cipher = null;

        if ($request->hasSession()) {
            $cipher = $request->session()->pull('pending_2fa_secret');
        }

        $cipher ??= Cache::pull($this->pendingSecretKey($request));

        if (!$cipher) {
            return ApiResponse::error('TWO_FACTOR_SETUP_EXPIRED', 'Start two-factor setup again.', 409);
        }

        $secret = Crypt::decryptString($cipher);
        if (!$google2fa->verifyKey($secret, $data['code'], 1)) {
            return ApiResponse::error('INVALID_TWO_FACTOR_CODE', 'The verification code is invalid.', 422);
        }

        $request->user()->forceFill(['two_factor_secret' => $secret, 'two_factor_enabled' => true])->save();

        if ($request->hasSession()) {
            $request->session()->regenerate();
        }

        return ApiResponse::success(['two_factor_enabled' => true]);
    }

    public function stepUp(Request $request, Google2FA $google2fa)
    {
        $data = $request->validate(['code' => ['required','digits:6']]);
        $merchant = $request->user();

        if (!$merchant->two_factor_enabled || !$google2fa->verifyKey($merchant->two_factor_secret, $data['code'], 1)) {
            return ApiResponse::error('INVALID_TWO_FACTOR_CODE', 'The verification code is invalid.', 422);
        }

        $verifiedUntil = now()->addSeconds((int) config('gateway.security.payout_step_up_ttl_seconds', 300));
        Cache::put('merchant:'.$merchant->id.':payout_step_up_verified_at', time(), $verifiedUntil);

        if ($request->hasSession()) {
            $request->session()->regenerate();
            $request->session()->put('payout_step_up_verified_at', time());
        }

        return ApiResponse::success(['verified_until' => $verifiedUntil->toIso8601String()]);
    }

    private function pendingSecretKey(Request $request): string
    {
        return 'merchant:'.$request->user()->id.':pending_2fa_secret';
    }
}