"""Server-side verification of a Google reCAPTCHA v2 ("I'm not a robot")
token submitted with a login attempt — see app/routers/auth.py's POST
/auth/login and GET /auth/recaptcha-config.

Off by default: enabled only once BOTH Settings.recaptcha_site_key and
recaptcha_secret_key are set (Settings.is_recaptcha_configured) — get a pair
at https://www.google.com/recaptcha/admin for the domain(s) FlowFabric is
served from. Both blank (the default) leaves every login exactly as it is
today; no other code path needs to know reCAPTCHA exists at all.
"""

import asyncio

import httpx

from app.core.config import settings
from app.core.tls import TRUSTSTORE_SSL_CONTEXT

_VERIFY_URL = "https://www.google.com/recaptcha/api/siteverify"


class RecaptchaError(Exception):
    """Message is written to be shown to the end user as-is (same convention
    as app/core/ocr.py's OcrUnavailableError). `status_code` is what the
    router should respond with: 400 for "you didn't pass" (no token, or
    Google says invalid/expired), 503 for "we couldn't even ask Google"."""

    def __init__(self, message: str, status_code: int = 400) -> None:
        super().__init__(message)
        self.status_code = status_code


def _sync_verify(token: str, remote_ip: str | None) -> dict:
    # Sync client inside asyncio.to_thread, using the shared truststore
    # context — see app/core/tls.py for why this can never be a plain
    # `httpx.AsyncClient` call (it can hang the entire server under
    # TLS-interception, reproduced directly on this project once already).
    data = {"secret": settings.recaptcha_secret_key, "response": token}
    if remote_ip:
        data["remoteip"] = remote_ip
    with httpx.Client(timeout=8.0, verify=TRUSTSTORE_SSL_CONTEXT) as client:
        resp = client.post(_VERIFY_URL, data=data)
        resp.raise_for_status()
        return resp.json()


async def verify_recaptcha_token(token: str | None, remote_ip: str | None = None) -> None:
    """No-op when reCAPTCHA isn't configured (the default) — every existing
    login flow keeps working unchanged. Raises RecaptchaError otherwise;
    callers should catch it and re-raise as an HTTPException with the same
    message and status_code (see app/routers/auth.py's login())."""
    if not settings.is_recaptcha_configured:
        return
    if not token or not token.strip():
        raise RecaptchaError("Please complete the reCAPTCHA challenge.")
    try:
        result = await asyncio.to_thread(_sync_verify, token, remote_ip)
    except httpx.HTTPError as exc:
        raise RecaptchaError("Couldn't verify the reCAPTCHA challenge right now — please try again.", status_code=503) from exc
    if not result.get("success"):
        raise RecaptchaError("reCAPTCHA verification failed — please try again.")
