<?php

namespace GriffinForms\Frontend\Html\Security;

use GriffinForms\Includes\Integrations\Categories\Captcha as CaptchaRegistry;
use GriffinForms\Frontend\Html\Security\Captcha\Manager as CaptchaManager;

class AntiSpam extends \GriffinForms\Frontend\Html\Security\Format
{
    private $errors = 0;
    private $error_notices = [];
    protected $antispam_options = [];
    protected $honeypot_class = 'griffinforms-formcontrol-a1b';
    protected $form_context_id = 0;
    protected $captcha_registry;
    protected $captcha_manager;
    protected $captcha_provider;

    protected function setAntiSpamOptions(): void
    {
        $options = $this->settings->getOptionsByGroup('antispam');
        $this->antispam_options = is_array($options) ? $options : [];
        $this->initializeCaptchaProvider();
    }

    public function setFormContext(int $form_id): void
    {
        $this->form_context_id = $form_id;
        $this->initializeCaptchaProvider();
    }

    public function getEnableHoneypot()
    {
        return (bool) ($this->antispam_options['enable_honeypot'] ?? false);
    }

    public function getHoneypotField()
    {
        if ($this->getEnableHoneypot()) {
            $this->honeypot_class = 'griffinforms-formcontrol-' . bin2hex(random_bytes(3));
            $html = '<div class="griffinforms-assist-field-wrap" aria-hidden="true" style="position:absolute !important;left:-10000px !important;top:0 !important;width:1px !important;height:1px !important;margin:0 !important;padding:0 !important;border:0 !important;overflow:hidden !important;clip:rect(0 0 0 0) !important;clip-path:inset(50%) !important;white-space:nowrap !important;opacity:0 !important;pointer-events:none !important;">';
            $html .= '<input type="text" class="' . esc_attr($this->honeypot_class) . '" data-gf-assist-field="1" value="" tabindex="-1" autocomplete="off" inputmode="text">';
            $html .= '</div>';
            return $html;
        }

        return '';
    }

    public function getHoneypotClass()
    {
        return $this->honeypot_class;
    }

    public function getCaptchaField(string $position): string
    {
        if (!$this->isCaptchaRequiredForPosition($position)) {
            return '';
        }

        $provider = $this->getCaptchaProvider();
        return $provider ? $provider->renderField($position) : '';
    }

    public function enqueueCaptchaScripts(): void
    {
        $provider = $this->getCaptchaProvider();
        if ($provider) {
            $provider->enqueueScripts();
        }
    }

    public function getCaptchaClientContext(string $position = ''): array
    {
        if (!$this->isCaptchaRequiredForPosition($position)) {
            return ['enabled' => false];
        }

        $provider = $this->getCaptchaProvider();
        if ($provider) {
            return $provider->getClientContext();
        }

        return ['enabled' => false];
    }

    public function hasErrors()
    {
        return $this->errors > 0;
    }

    public function getErrorNotices()
    {
        return $this->error_notices;
    }

    public function assessSpam($form_data)
    {
        if (!isset($form_data['antispam_data'])) {
            $this->errors += 1;
            $this->error_notices[] = __('Important security data missing with form data.', 'griffinforms-form-builder');
            return;
        }

        $antispam_raw = $form_data['antispam_data'];
        if (is_string($antispam_raw)) {
            $antispam_data = json_decode($antispam_raw);
        } elseif (is_array($antispam_raw)) {
            $antispam_data = (object) $antispam_raw;
        } else {
            $antispam_data = null;
        }

        if (!is_object($antispam_data)) {
            $this->errors += 1;
            $this->error_notices[] = __('Formatting issues with form\'s security data.', 'griffinforms-form-builder');
            return;
        }

        if ($this->getEnableHoneypot()) {
            if (isset($antispam_data->honeypot) && trim((string) $antispam_data->honeypot) !== '') {
                $this->errors += 1;
                $this->error_notices[] = __('Unable to submit. Honeypot security assessment failed.', 'griffinforms-form-builder');
            }
        }

        $provider = $this->getCaptchaProvider();
        $position = isset($form_data['position']) ? sanitize_key($form_data['position']) : '';
        if ($provider && $provider->isEnabled() && $this->isCaptchaRequiredForPosition($position)) {
            $result = $provider->validateSubmission($antispam_data, $form_data);
            if (!($result['success'] ?? false)) {
                $this->errors += 1;
                $this->error_notices[] = $result['message'] ?? __('Unable to submit. CAPTCHA assessment failed.', 'griffinforms-form-builder');
                $this->logCaptchaSkip('CAPTCHA validation failed for position "' . $position . '".');
            }
        }
    }

    protected function bootstrapCaptchaServices(): void
    {
        if (!$this->captcha_registry) {
            $this->captcha_registry = CaptchaRegistry::getInstance();
        }

        if (!$this->captcha_manager) {
            $this->captcha_manager = CaptchaManager::getInstance();
        }
    }

    protected function initializeCaptchaProvider(): void
    {
        $this->bootstrapCaptchaServices();
        $this->captcha_provider = null;

        if (!$this->captcha_registry || !$this->captcha_manager) {
            return;
        }

        $integration = $this->captcha_registry->getActiveIntegration($this->form_context_id);
        if (!$integration) {
            return;
        }

        if (method_exists($integration, 'isEnabledForForm') && !$integration->isEnabledForForm($this->form_context_id)) {
            return;
        }

        $provider_id = $this->captcha_registry->getActiveProviderId();
        if (!$provider_id) {
            $this->logCaptchaSkip('No active CAPTCHA provider configured; skipping CAPTCHA rendering.');
            return;
        }

        $provider = $this->captcha_manager->create($provider_id, $this->antispam_options, $this->form_context_id);
        if ($provider && $provider->isEnabled()) {
            $this->captcha_provider = $provider;
        } else {
            $this->logCaptchaSkip(sprintf('CAPTCHA provider "%s" could not be initialized; CAPTCHA intentionally skipped.', $provider_id));
        }
    }

    protected function getCaptchaProvider()
    {
        if ($this->captcha_provider && $this->captcha_provider->isEnabled()) {
            return $this->captcha_provider;
        }

        return null;
    }

    protected function isCaptchaRequiredForPosition(string $position): bool
    {
        if (empty($position)) {
            return true;
        }

        return in_array($position, ['single', 'first', 'middle', 'last'], true);
    }

    protected function logCaptchaSkip(string $message): void
    {
        if (!isset($this->log)) {
            return;
        }

        $form_id = (int) $this->form_context_id;
        $this->log->add(
            'warning',
            'form',
            $form_id,
            get_current_user_id(),
            $message,
            'security'
        );
    }
}
