<?php

namespace App\Services;

use App\Models\MarketplacePurchase;
use App\Models\Setting;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;

class CaptchaService
{
    public const CONTEXT_CONTACT = 'contact';

    public const CONTEXT_RESERVATION = 'reservation';

    public const CONTEXT_NEWSLETTER = 'newsletter';

    public const CONTEXT_CHECKOUT = 'checkout';

    public function isLicensed(): bool
    {
        return MarketplacePurchase::hasPurchased('plugin', 'captcha-protection');
    }

    public function getProvider(): string
    {
        return Setting::get('captcha_provider', 'cloudflare') === 'google' ? 'google' : 'cloudflare';
    }

    public function getSiteKey(): string
    {
        return (string) Setting::get('captcha_site_key', '');
    }

    public function getSecretKey(): string
    {
        return (string) Setting::get('captcha_secret_key', '');
    }

    public function getGoogleType(): string
    {
        return Setting::get('captcha_google_type', 'v2') === 'v3' ? 'v3' : 'v2';
    }

    public function getScoreThreshold(): float
    {
        return (float) Setting::get('captcha_score_threshold', 0.5);
    }

    public function isReady(): bool
    {
        if (! $this->isLicensed()) {
            return false;
        }

        return $this->getSiteKey() !== '' && $this->getSecretKey() !== '';
    }

    public function shouldVerify(string $context): bool
    {
        if (! $this->isReady()) {
            return false;
        }

        return match ($context) {
            self::CONTEXT_CONTACT => $this->boolSetting('captcha_on_contact', true),
            self::CONTEXT_RESERVATION => $this->boolSetting('captcha_on_reservation', true),
            self::CONTEXT_NEWSLETTER => $this->boolSetting('captcha_on_newsletter', true),
            self::CONTEXT_CHECKOUT => $this->boolSetting('captcha_on_checkout', true),
            default => false,
        };
    }

    protected function boolSetting(string $key, bool $default): bool
    {
        if (! Setting::where('key', $key)->exists()) {
            return $default;
        }

        return filter_var(Setting::get($key), FILTER_VALIDATE_BOOLEAN);
    }

    /**
     * @return array{ok: bool, error?: string}
     */
    public function verifyRequest(Request $request): array
    {
        $ip = $request->ip();
        $provider = $this->getProvider();

        if ($provider === 'cloudflare') {
            $token = $request->input('cf-turnstile-response');
            if (empty($token)) {
                return ['ok' => false, 'error' => 'Captcha manquant.'];
            }

            $response = Http::asForm()->timeout(10)->post('https://challenges.cloudflare.com/turnstile/v0/siteverify', [
                'secret' => $this->getSecretKey(),
                'response' => $token,
                'remoteip' => $ip,
            ]);

            if (! $response->successful()) {
                return ['ok' => false, 'error' => 'Erreur de vérification du captcha.'];
            }

            $data = $response->json();
            if (! empty($data['success'])) {
                return ['ok' => true];
            }

            return ['ok' => false, 'error' => 'Captcha invalide ou expiré.'];
        }

        // Google reCAPTCHA
        $token = $request->input('g-recaptcha-response');
        if (empty($token)) {
            return ['ok' => false, 'error' => 'Captcha manquant.'];
        }

        $response = Http::asForm()->timeout(10)->post('https://www.google.com/recaptcha/api/siteverify', [
            'secret' => $this->getSecretKey(),
            'response' => $token,
            'remoteip' => $ip,
        ]);

        if (! $response->successful()) {
            return ['ok' => false, 'error' => 'Erreur de vérification du captcha.'];
        }

        $data = $response->json();
        if (empty($data['success'])) {
            return ['ok' => false, 'error' => 'Captcha invalide ou expiré.'];
        }

        if ($this->getGoogleType() === 'v3') {
            $score = (float) ($data['score'] ?? 0);
            if ($score < $this->getScoreThreshold()) {
                return ['ok' => false, 'error' => 'Score de confiance trop faible, réessayez.'];
            }
        }

        return ['ok' => true];
    }

    /**
     * Données pour le partial Blade (widget + scripts).
     *
     * @return array{show: bool, provider: string, site_key: string, google_type: string}
     */
    public function frontendPayload(string $context): array
    {
        if (! $this->shouldVerify($context)) {
            return ['show' => false, 'provider' => '', 'site_key' => '', 'google_type' => 'v2'];
        }

        return [
            'show' => true,
            'provider' => $this->getProvider(),
            'site_key' => $this->getSiteKey(),
            'google_type' => $this->getGoogleType(),
        ];
    }
}
