<?php

namespace App\Support;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

/**
 * reCAPTCHA helper — single source of truth for "is captcha required on
 * this request?" and "is this token valid?".
 *
 * Settings live in security_settings (Admin → Settings → Security):
 *   - captcha_enabled     (bool toggle)
 *   - captcha_site_key    (rendered on the login Blade as data-sitekey)
 *   - captcha_secret_key  (used server-side at /siteverify)
 *
 * Supports both reCAPTCHA v2 (checkbox) and v3 (invisible) — the same
 * /siteverify endpoint handles both. Site key shape tells you which the
 * admin configured; the Blade picks the right widget snippet.
 */
class Captcha
{
    private const VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify';

    /**
     * True only when admin has flipped captcha_enabled ON AND both keys
     * are filled in. A half-configured captcha (toggle on, keys blank)
     * silently disables — better than locking every user out.
     */
    public static function isEnabled(): bool
    {
        $s = SecuritySettings::get();
        return (bool) ($s['captcha_enabled'] ?? false)
            && !empty($s['captcha_site_key'])
            && !empty($s['captcha_secret_key']);
    }

    public static function siteKey(): string
    {
        return (string) (SecuritySettings::get()['captcha_site_key'] ?? '');
    }

    /**
     * Verify a `g-recaptcha-response` token from the login form against
     * Google's /siteverify. Returns true ONLY when Google says success.
     *
     * Safety rails:
     *   - 5s timeout: a slow /siteverify must NOT block login for 30s+.
     *   - Network failure → returns false. Admins running captcha must
     *     accept some availability cost — better fail-closed than
     *     fail-open (which would render captcha a no-op the moment
     *     Google is unreachable).
     *   - Empty token → false without calling the API.
     */
    public static function verify(?string $token, ?string $ip = null): bool
    {
        if (!self::isEnabled()) {
            return true; // captcha not enforced → nothing to verify
        }

        if (!is_string($token) || trim($token) === '') {
            return false;
        }

        $secret = (string) (SecuritySettings::get()['captcha_secret_key'] ?? '');
        if ($secret === '') {
            return false;
        }

        try {
            $resp = Http::asForm()->timeout(5)->post(self::VERIFY_URL, [
                'secret'   => $secret,
                'response' => $token,
                'remoteip' => $ip,
            ]);

            $body = $resp->json();
            if (!is_array($body)) return false;

            $ok = (bool) ($body['success'] ?? false);

            if (!$ok) {
                // Log error codes (timeout-or-duplicate, invalid-input-secret,
                // invalid-input-response, etc.) so admins can debug a
                // misconfigured captcha.
                Log::warning('Captcha verification failed', [
                    'error_codes' => $body['error-codes'] ?? [],
                    'hostname'    => $body['hostname'] ?? null,
                ]);
            }

            return $ok;
        } catch (\Throwable $e) {
            Log::warning('Captcha /siteverify call failed: ' . $e->getMessage());
            return false;
        }
    }
}
