<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Http\Requests\OtpVerificationRequest;
use App\Services\OtpService;
use App\Services\AuthenticationService;
use App\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Illuminate\Support\Facades\Auth;

class OtpController extends Controller
{
    protected OtpService $otpService;
    protected AuthenticationService $authService;

    public function __construct(OtpService $otpService, AuthenticationService $authService)
    {
        $this->otpService = $otpService;
        $this->authService = $authService;
    }

    /**
     * Show the OTP verification form.
     */
    public function showOtpForm(): View
    {
        if (!session('auth.user_id')) {
            return redirect()->route('login');
        }

        $user = User::find(session('auth.user_id'));

        if (!$user) {
            return redirect()->route('login');
        }

        $remainingAttempts = $this->otpService->remainingAttempts($user);
        $expiresInSeconds = $this->otpService->expiresInSeconds($user);

        return view('auth.otp-verify', compact('remainingAttempts', 'expiresInSeconds'));
    }

    /**
     * Verify the OTP code.
     */
    public function verify(OtpVerificationRequest $request): RedirectResponse
    {
        $userId = session('auth.user_id');

        if (!$userId) {
            return redirect()->route('login')
                ->withErrors(['otp' => 'Session expired. Please login again.']);
        }

        $user = User::find($userId);

        if (!$user) {
            return redirect()->route('login')
                ->withErrors(['otp' => 'User not found. Please login again.']);
        }

        // Verify OTP
        $result = $this->otpService->verify($user, $request->getOtp());

        if (!$result['success']) {
            $remaining = $this->otpService->remainingAttempts($user);

            if ($remaining <= 0) {
                // OTP locked, need to request new one
                return redirect()->route('otp.resend')
                    ->withErrors(['otp' => 'Too many failed attempts. Please request a new code.']);
            }

            return back()->withErrors(['otp' => $result['message']])
                ->with('remainingAttempts', $remaining);
        }

        // OTP verified, complete login
        Auth::login($user, session('auth.remember', false));
        $this->authService->completeAuthentication($user, $request);

        // Clear session data
        session()->forget(['auth.user_id', 'auth.remember']);

        // Check if 2FA is also required
        if ($this->authService->requires2FA($user)) {
            session(['auth.user_id' => $user->id]);
            Auth::logout();
            return redirect()->route('two-factor.challenge');
        }

        return redirect()->intended($user->getDashboardUrl())
            ->with('status', 'Login successful!');
    }

    /**
     * Resend OTP code.
     */
    public function resend(Request $request): RedirectResponse
    {
        $userId = session('auth.user_id');

        if (!$userId) {
            return redirect()->route('login');
        }

        $user = User::find($userId);

        if (!$user) {
            return redirect()->route('login');
        }

        // Check if we already have a valid pending OTP
        if ($this->otpService->hasPendingOtp($user)) {
            $expiresIn = $this->otpService->expiresInSeconds($user);
            return back()->withErrors(['otp' => "Please wait {$expiresIn} seconds before requesting a new code."]);
        }

        // Generate and send new OTP
        $this->otpService->generateAndSend($user);

        return redirect()->route('otp.verify')
            ->with('status', 'A new verification code has been sent to your email.');
    }

    /**
     * Cancel OTP verification and redirect to login.
     */
    public function cancel(): RedirectResponse
    {
        session()->forget(['auth.user_id', 'auth.remember']);
        return redirect()->route('login');
    }
}
