<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Models\ActivityLog;
use App\Models\TrustedDevice;
use App\Notifications\TwoFactorStatusChanged;
use Illuminate\Http\Request;
use PragmaRX\Google2FA\Google2FA;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cookie;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Str;

class TwoFactorController extends Controller
{
    protected $google2fa;

    public function __construct()
    {
        $this->google2fa = new Google2FA();
    }

    /**
     * Afișează pagina de setări 2FA
     */
    public function index()
    {
        $user = Auth::user();

        // Obține dispozitivele trusted
        $trustedDevices = TrustedDevice::where('user_id', $user->id)
            ->where('expires_at', '>', now())
            ->orderBy('last_used_at', 'desc')
            ->get();

        // Calculează coduri de recuperare rămase
        $recoveryCodesCount = 0;
        if ($user->two_factor_recovery_codes) {
            $codes = json_decode(decrypt($user->two_factor_recovery_codes), true);
            $recoveryCodesCount = is_array($codes) ? count($codes) : 0;
        }

        return view('auth.two-factor', [
            'two_factor_enabled' => $user->two_factor_enabled,
            'has_recovery_codes' => !empty($user->two_factor_recovery_codes),
            'recovery_codes_count' => $recoveryCodesCount,
            'trusted_devices' => $trustedDevices
        ]);
    }

    /**
     * Generează secret și QR code pentru activare 2FA
     */
    public function enable()
    {
        $user = Auth::user();

        // Dacă 2FA este deja activat, returnează eroare
        if ($user->two_factor_enabled) {
            return response()->json([
                'success' => false,
                'message' => 'Autentificarea 2FA este deja activată.'
            ], 400);
        }

        // Generează secret nou
        $secret = $this->google2fa->generateSecretKey();

        // Salvează secret-ul (neconfirmat încă) cu timestamp pentru expirare
        $user->two_factor_secret = encrypt($secret);
        $user->save();

        // Salvează timestamp-ul generării în sesiune (expiră în 10 minute)
        session(['2fa_secret_generated_at' => now()->timestamp]);

        // Generează QR code URL
        $qrCodeUrl = $this->google2fa->getQRCodeUrl(
            config('app.name'),
            $user->email,
            $secret
        );

        // Generează QR code inline
        $qrCode = $this->generateQRCode($qrCodeUrl);

        return response()->json([
            'success' => true,
            'secret' => $secret,
            'qr_code' => $qrCode
        ]);
    }

    /**
     * Confirmă și activează 2FA
     */
    public function confirm(Request $request)
    {
        $request->validate([
            'code' => 'required|string|size:6'
        ]);

        $user = Auth::user();

        // Verifică dacă utilizatorul are un secret
        if (!$user->two_factor_secret) {
            return response()->json([
                'success' => false,
                'message' => 'Nu există un secret 2FA generat. Te rugăm să generezi un nou QR code.'
            ], 400);
        }

        // Verifică dacă QR code-ul a expirat (10 minute)
        $generatedAt = session('2fa_secret_generated_at');
        $expirationMinutes = 10;

        if (!$generatedAt || (now()->timestamp - $generatedAt) > ($expirationMinutes * 60)) {
            // Șterge secret-ul expirat
            $user->two_factor_secret = null;
            $user->save();
            session()->forget('2fa_secret_generated_at');

            return response()->json([
                'success' => false,
                'message' => 'QR code-ul a expirat. Te rugăm să generezi un nou QR code.',
                'expired' => true
            ], 400);
        }

        $secret = decrypt($user->two_factor_secret);

        // Verifică codul
        $valid = $this->google2fa->verifyKey($secret, $request->code);

        if (!$valid) {
            return response()->json([
                'success' => false,
                'message' => 'Codul introdus este invalid.'
            ], 400);
        }

        // Curăță sesiunea
        session()->forget('2fa_secret_generated_at');

        // Activează 2FA și generează coduri de recuperare
        $recoveryCodes = $this->generateRecoveryCodes();

        $user->two_factor_enabled = true;
        $user->two_factor_confirmed_at = now();
        $user->two_factor_recovery_codes = encrypt(json_encode($recoveryCodes));
        $user->save();

        Log::info('2FA activat pentru utilizatorul: ' . $user->email);

        // Audit log
        ActivityLog::log('2fa_enabled', '2FA activat cu succes', 'User', $user->id, [
            'recovery_codes_count' => count($recoveryCodes)
        ]);

        // Notificare email
        $user->notify(new TwoFactorStatusChanged('enabled', request()->ip(), request()->userAgent()));

        return response()->json([
            'success' => true,
            'message' => 'Autentificare cu doi factori activată cu succes!',
            'recovery_codes' => $recoveryCodes
        ]);
    }

    /**
     * Dezactivează 2FA
     */
    public function disable(Request $request)
    {
        $request->validate([
            'password' => 'required|string'
        ]);

        $user = Auth::user();

        // Verifică parola
        if (!Hash::check($request->password, $user->password)) {
            return response()->json([
                'success' => false,
                'message' => 'Parola introdusă este incorectă.'
            ], 400);
        }

        // Dezactivează 2FA
        $user->two_factor_enabled = false;
        $user->two_factor_secret = null;
        $user->two_factor_recovery_codes = null;
        $user->two_factor_confirmed_at = null;
        $user->save();

        // Șterge și dispozitivele trusted
        TrustedDevice::where('user_id', $user->id)->delete();

        Log::info('2FA dezactivat pentru utilizatorul: ' . $user->email);

        // Audit log
        ActivityLog::log('2fa_disabled', '2FA dezactivat', 'User', $user->id);

        // Notificare email
        $user->notify(new TwoFactorStatusChanged('disabled', request()->ip(), request()->userAgent()));

        return response()->json([
            'success' => true,
            'message' => 'Autentificare cu doi factori dezactivată cu succes!'
        ]);
    }

    /**
     * Regenerează coduri de recuperare
     */
    public function regenerateRecoveryCodes(Request $request)
    {
        $request->validate([
            'password' => 'required|string'
        ]);

        $user = Auth::user();

        // Verifică parola
        if (!Hash::check($request->password, $user->password)) {
            return response()->json([
                'success' => false,
                'message' => 'Parola introdusă este incorectă.'
            ], 400);
        }

        if (!$user->two_factor_enabled) {
            return response()->json([
                'success' => false,
                'message' => 'Autentificarea 2FA nu este activată.'
            ], 400);
        }

        // Generează noi coduri
        $recoveryCodes = $this->generateRecoveryCodes();
        $user->two_factor_recovery_codes = encrypt(json_encode($recoveryCodes));
        $user->save();

        Log::info('Coduri de recuperare 2FA regenerate pentru: ' . $user->email);

        // Audit log
        ActivityLog::log('2fa_codes_regenerated', 'Coduri de recuperare 2FA regenerate', 'User', $user->id, [
            'codes_count' => count($recoveryCodes)
        ]);

        // Notificare email
        $user->notify(new TwoFactorStatusChanged('codes_regenerated', request()->ip(), request()->userAgent()));

        return response()->json([
            'success' => true,
            'message' => 'Coduri de recuperare regenerate cu succes!',
            'recovery_codes' => $recoveryCodes
        ]);
    }

    /**
     * Verifică codul 2FA la login
     */
    public function verify(Request $request)
    {
        $request->validate([
            'code' => 'required|string',
            'trust_device' => 'nullable|boolean'
        ]);

        $user = Auth::user();

        // Rate limiting - max 5 încercări pe minut
        $throttleKey = $this->get2FAThrottleKey($user, $request);

        if (RateLimiter::tooManyAttempts($throttleKey, 5)) {
            $seconds = RateLimiter::availableIn($throttleKey);
            Log::warning('2FA rate limit exceeded pentru: ' . $user->email . ' de la IP: ' . $request->ip());

            // Audit log - rate limit exceeded
            ActivityLog::log('2fa_rate_limited', 'Prea multe încercări 2FA - blocat temporar', 'User', $user->id, [
                'blocked_seconds' => $seconds
            ]);

            return response()->json([
                'success' => false,
                'message' => trans('auth.2fa_throttle', ['seconds' => $seconds]),
                'retry_after' => $seconds
            ], 429);
        }

        if (!$user->two_factor_enabled) {
            return response()->json([
                'success' => false,
                'message' => 'Autentificarea 2FA nu este activată.'
            ], 400);
        }

        $code = $request->code;

        // Verifică dacă este cod normal sau cod de recuperare
        if (strlen($code) === 6) {
            // Cod normal din aplicație
            $secret = decrypt($user->two_factor_secret);
            $valid = $this->google2fa->verifyKey($secret, $code, 2); // 2 = window tolerance

            if ($valid) {
                // Curăță rate limiter-ul la succes
                RateLimiter::clear($throttleKey);

                // Marchează sesiunea ca verificată 2FA
                session(['2fa_verified' => true]);

                // Audit log - verificare reușită
                ActivityLog::log('2fa_verified', 'Verificare 2FA reușită (cod aplicație)', 'User', $user->id);

                // Trust device dacă e solicitat
                $response = response()->json([
                    'success' => true,
                    'message' => 'Autentificare reușită!',
                    'redirect' => session()->pull('url.intended', route('dashboard'))
                ]);

                if ($request->boolean('trust_device')) {
                    $response = $this->addTrustedDeviceCookie($response, $user, $request);
                }

                return $response;
            }
        } else {
            // Cod de recuperare
            $recoveryCodes = json_decode(decrypt($user->two_factor_recovery_codes), true);

            if (in_array($code, $recoveryCodes)) {
                // Curăță rate limiter-ul la succes
                RateLimiter::clear($throttleKey);

                // Șterge codul folosit
                $recoveryCodes = array_values(array_diff($recoveryCodes, [$code]));
                $user->two_factor_recovery_codes = encrypt(json_encode($recoveryCodes));
                $user->save();

                // Marchează sesiunea ca verificată 2FA
                session(['2fa_verified' => true]);

                Log::warning('Cod de recuperare 2FA folosit pentru: ' . $user->email);

                // Audit log - verificare reușită cu cod recuperare
                ActivityLog::log('2fa_recovery_used', 'Verificare 2FA cu cod de recuperare', 'User', $user->id, [
                    'codes_remaining' => count($recoveryCodes)
                ]);

                $response = response()->json([
                    'success' => true,
                    'message' => 'Autentificare reușită cu cod de recuperare!',
                    'warning' => 'Ați folosit un cod de recuperare. Vă recomandăm să regenerați codurile.',
                    'redirect' => session()->pull('url.intended', route('dashboard'))
                ]);

                if ($request->boolean('trust_device')) {
                    $response = $this->addTrustedDeviceCookie($response, $user, $request);
                }

                return $response;
            }
        }

        // Incrementează counter pentru rate limiting
        RateLimiter::hit($throttleKey, 60); // decay în 60 secunde

        $attemptsLeft = 5 - RateLimiter::attempts($throttleKey);

        // Audit log - verificare eșuată
        ActivityLog::log('2fa_failed', 'Verificare 2FA eșuată', 'User', $user->id, [
            'attempts_left' => max(0, $attemptsLeft)
        ]);

        return response()->json([
            'success' => false,
            'message' => 'Codul introdus este invalid.',
            'attempts_left' => max(0, $attemptsLeft)
        ], 400);
    }

    /**
     * Adaugă cookie pentru trusted device
     */
    protected function addTrustedDeviceCookie($response, $user, Request $request)
    {
        $trustedDevice = TrustedDevice::createForUser(
            $user,
            $request->ip(),
            $request->userAgent() ?? 'Unknown',
            30 // 30 zile valid
        );

        Log::info('Trusted device adăugat pentru: ' . $user->email . ' - ' . $trustedDevice->device_name);

        // Audit log
        ActivityLog::log('2fa_device_trusted', 'Dispozitiv adăugat ca trusted', 'TrustedDevice', $trustedDevice->id, [
            'device_name' => $trustedDevice->device_name,
            'expires_at' => $trustedDevice->expires_at->toDateTimeString()
        ]);

        // Notificare email
        $user->notify(new TwoFactorStatusChanged('device_trusted', $request->ip(), $request->userAgent(), $trustedDevice->device_name));

        // Cookie-ul va expira în 30 de zile
        // Secure = true doar în producție (HTTPS)
        $isSecure = $request->isSecure() || config('app.env') === 'production';

        // Obține path-ul corect din config
        $cookiePath = config('session.path', '/');

        // Folosim Cookie::queue() pentru a garanta că cookie-ul ajunge în browser
        Cookie::queue(
            '2fa_trusted_device',
            $trustedDevice->device_token,
            60 * 24 * 30, // 30 zile în minute
            $cookiePath,
            config('session.domain'),
            $isSecure, // secure doar pe HTTPS
            true,  // httpOnly
            false, // raw
            config('session.same_site', 'lax')
        );

        Log::info('Cookie 2fa_trusted_device queued', [
            'token_prefix' => substr($trustedDevice->device_token, 0, 10),
            'path' => $cookiePath,
            'secure' => $isSecure
        ]);

        return $response;
    }

    /**
     * Obține cheia pentru rate limiting 2FA
     */
    protected function get2FAThrottleKey($user, Request $request): string
    {
        return Str::lower('2fa_verify|' . $user->id . '|' . $request->ip());
    }

    /**
     * Generează coduri de recuperare
     */
    protected function generateRecoveryCodes(): array
    {
        $codes = [];
        for ($i = 0; $i < 10; $i++) {
            $codes[] = strtoupper(substr(str_replace(['+', '/', '='], '', base64_encode(random_bytes(12))), 0, 16));
        }
        return $codes;
    }

    /**
     * Generează QR code inline (SVG)
     */
    protected function generateQRCode(string $url): string
    {
        $renderer = new \BaconQrCode\Renderer\ImageRenderer(
            new \BaconQrCode\Renderer\RendererStyle\RendererStyle(250),
            new \BaconQrCode\Renderer\Image\SvgImageBackEnd()
        );

        $writer = new \BaconQrCode\Writer($renderer);

        return $writer->writeString($url);
    }

    /**
     * Revocă un dispozitiv trusted
     */
    public function revokeTrustedDevice(Request $request, $deviceId)
    {
        $user = Auth::user();

        $device = TrustedDevice::where('id', $deviceId)
            ->where('user_id', $user->id)
            ->first();

        if (!$device) {
            return response()->json([
                'success' => false,
                'message' => 'Dispozitivul nu a fost găsit.'
            ], 404);
        }

        $deviceName = $device->device_name;
        $deviceId = $device->id;
        $device->delete();

        Log::info('Trusted device revocat pentru: ' . $user->email . ' - ' . $deviceName);

        // Audit log
        ActivityLog::log('2fa_device_revoked', 'Dispozitiv trusted revocat', 'TrustedDevice', $deviceId, [
            'device_name' => $deviceName
        ]);

        // Email notificare - dispozitiv revocat
        $user->notify(new TwoFactorStatusChanged('device_revoked', request()->ip(), request()->userAgent(), $deviceName));

        return response()->json([
            'success' => true,
            'message' => 'Dispozitivul "' . $deviceName . '" a fost revocat.'
        ]);
    }

    /**
     * Revocă toate dispozitivele trusted
     */
    public function revokeAllTrustedDevices(Request $request)
    {
        $user = Auth::user();

        $count = TrustedDevice::where('user_id', $user->id)->delete();

        // Invalidează și cookie-ul curent
        Cookie::queue(Cookie::forget('2fa_trusted_device'));

        // Resetează sesiunea 2FA
        session()->forget('2fa_verified');

        Log::info('Toate trusted devices revocate pentru: ' . $user->email . ' (' . $count . ' dispozitive)');

        // Audit log
        ActivityLog::log('2fa_all_devices_revoked', 'Toate dispozitivele trusted revocate', 'User', $user->id, [
            'devices_count' => $count
        ]);

        // Email notificare - toate dispozitivele revocate
        if ($count > 0) {
            $user->notify(new TwoFactorStatusChanged('all_devices_revoked', $request->ip(), $request->userAgent()));
        }

        return response()->json([
            'success' => true,
            'message' => $count . ' dispozitiv(e) au fost revocate.'
        ]);
    }
}
