<?php

namespace App\Http\Requests\Auth;

use Illuminate\Auth\Events\Lockout;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;

class LoginRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'email' => [
                'required',
                'string',
                'email',
                function ($attribute, $value, $fail) {
                    if (!str_ends_with(strtolower($value), '@gmail.com')) {
                        $fail('Hanya alamat email @gmail.com yang diizinkan untuk masuk ke sistem ini.');
                    }
                },
            ],
            'password' => ['required', 'string'],
        ];
    }

    public function messages(): array
    {
        return [
            'email.required' => 'Email harus diisi.',
            'email.string' => 'Email harus berupa teks.',
            'email.email' => 'Email tidak valid.',
            'password.required' => 'Password harus diisi.',
            'password.string' => 'Password harus berupa teks.',
        ];
    }

    public function authenticate(): void
    {
        $this->ensureIsNotRateLimited();

        if (! Auth::attempt($this->only('email', 'password'), $this->boolean('remember'))) {
            RateLimiter::hit($this->throttleKey(), 600);

            if (RateLimiter::tooManyAttempts($this->throttleKey(), 5)) {
                $this->storeLockoutCache(600);
            }

            throw ValidationException::withMessages([
                'email' => 'Email atau password salah.',
            ]);
        }

        RateLimiter::clear($this->throttleKey());
        $this->clearLockoutCache();
    }

    public function validateCredentials(): void
    {
        $this->ensureIsNotRateLimited();

        if (! Auth::validate($this->only('email', 'password'))) {
            RateLimiter::hit($this->throttleKey(), 600);

            if (RateLimiter::tooManyAttempts($this->throttleKey(), 5)) {
                $this->storeLockoutCache(600);
            }

            throw ValidationException::withMessages([
                'email' => 'Email atau password salah.',
            ]);
        }

        RateLimiter::clear($this->throttleKey());
        $this->clearLockoutCache();
    }

    public function ensureIsNotRateLimited(): void
    {
        if (! RateLimiter::tooManyAttempts($this->throttleKey(), 5)) {
            return;
        }

        event(new Lockout($this));

        $seconds = RateLimiter::availableIn($this->throttleKey());
        $minutes = ceil($seconds / 60);

        // Perbarui cache admin dengan sisa waktu terkini
        $this->storeLockoutCache($seconds);

        // Prefix "LOCKOUT:{detik}" dibaca oleh blade login untuk countdown realtime
        throw ValidationException::withMessages([
            'email' => "LOCKOUT:{$seconds} Akun sementara diblokir karena lebih dari 5 kali salah login. Silakan tunggu {$minutes} menit untuk mencoba lagi.",
        ]);
    }

    /**
     * Simpan metadata lockout ke cache agar halaman admin bisa membacanya.
     */
    private function storeLockoutCache(int $seconds): void
    {
        $email    = strtolower(trim($this->string('email')));
        $cacheKey = 'login_locked:' . $email;

        cache()->put($cacheKey, [
            'email'      => $email,
            'ip'         => $this->ip(),
            'expires_at' => time() + $seconds,
            'locked_at'  => time(),
        ], $seconds + 10);

        // Simpan throttle key agar admin bisa clear RateLimiter
        cache()->put(
            'login_locked_throttle_key:' . $email,
            $this->throttleKey(),
            $seconds + 10
        );
    }

    private function clearLockoutCache(): void
    {
        $email = strtolower(trim($this->string('email')));
        cache()->forget('login_locked:' . $email);
        cache()->forget('login_locked_throttle_key:' . $email);
    }

    public function throttleKey(): string
    {
        return Str::transliterate(Str::lower($this->string('email')).'|'.$this->ip());
    }
}