<?php

namespace App\Services\Security\Captcha;

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

class TurnstileCaptchaProvider implements CaptchaProviderInterface
{
    private const DEFAULT_VERIFY_URL = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';

    private const DEFAULT_SCRIPT_URL = 'https://challenges.cloudflare.com/turnstile/v0/api.js';

    public function name(): string
    {
        return 'turnstile';
    }

    public function isEnabled(): bool
    {
        return (bool) config('services.turnstile.enabled', false)
            && $this->siteKey() !== ''
            && (string) config('services.turnstile.secret_key', '') !== '';
    }

    public function siteKey(): string
    {
        return (string) config('services.turnstile.site_key', '');
    }

    public function inputName(): string
    {
        return 'cf-turnstile-response';
    }

    public function scriptUrl(): string
    {
        return (string) config('services.turnstile.script_url', self::DEFAULT_SCRIPT_URL);
    }

    public function verify(string $token, ?string $ip = null): bool
    {
        if (! $this->isEnabled()) {
            return true;
        }

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

        try {
            $response = Http::asForm()
                ->timeout((int) config('services.turnstile.timeout', 5))
                ->post((string) config('services.turnstile.verify_url', self::DEFAULT_VERIFY_URL), [
                    'secret' => (string) config('services.turnstile.secret_key', ''),
                    'response' => $token,
                ]);

            if ($response->failed()) {
                Log::info('turnstile verification rejected registration attempt', [
                    'ip' => $ip,
                    'hostname' => data_get($response->json(), 'hostname'),
                    'error_codes' => data_get($response->json(), 'error-codes', []),
                ]);

                return false;
            }

            $success = (bool) data_get($response->json(), 'success', false);

            if (! $success) {
                Log::info('turnstile verification rejected registration attempt', [
                    'ip' => $ip,
                    'hostname' => data_get($response->json(), 'hostname'),
                    'error_codes' => data_get($response->json(), 'error-codes', []),
                ]);
            }

            return $success;
        } catch (\Throwable $exception) {
            Log::warning('turnstile verification request failed', [
                'message' => $exception->getMessage(),
                'ip' => $ip,
            ]);

            return (bool) config('services.turnstile.fail_open', false);
        }
    }
}
