<?php
declare(strict_types=1);

namespace Ekesto\CacheInvalidator\Integrations\Forms\Adapters;

use Ekesto\CacheInvalidator\Support\Debug;
use Ekesto\CacheInvalidator\Integrations\Forms\FormAdapterInterface;

/**
 * Gravity Forms adapter.
 */
final class GravityFormsAdapter implements FormAdapterInterface
{
    use NormalizesFormIds;

    /**
     * Return adapter key.
     *
     * @return string
     */
    public function key(): string
    {
        return 'gravity_forms';
    }

    /**
     * Return adapter label.
     *
     * @return string
     */
    public function label(): string
    {
        return 'Gravity Forms';
    }

    /**
     * Return whether Gravity Forms is available.
     *
     * @return bool
     */
    public function isAvailable(): bool
    {
        return defined('GF_COMMON_VERSION') || class_exists('GFAPI');
    }

    /**
     * Register form change hooks.
     *
     * @param callable $onFormChanged Change callback.
     * @return void
     */
    public function registerHooks(callable $onFormChanged): void
    {
        Debug::verbose('forms adapter hooks registered: gravity_forms');

        add_action('gform_after_save_form', static function ($form, bool $isNew) use ($onFormChanged): void {
            $rawFormId = (is_array($form) && isset($form['id'])) ? (string) $form['id'] : '';
            Debug::verbose(sprintf(
                'forms adapter event: gravity_forms hook=gform_after_save_form form_id=%s is_new=%s',
                trim($rawFormId),
                $isNew ? 'yes' : 'no'
            ));
            if (!is_array($form)) {
                Debug::warn('forms adapter anomaly: gravity_forms hook=gform_after_save_form reason=invalid_form_payload');
                return;
            }

            $formId = isset($form['id']) ? (string) $form['id'] : '';
            if ($formId === '') {
                Debug::warn('forms adapter anomaly: gravity_forms hook=gform_after_save_form reason=empty_form_id');
                return;
            }

            Debug::verbose(sprintf(
                'forms adapter dispatch: gravity_forms form_id=%s hook=gform_after_save_form event=%s',
                $formId,
                $isNew ? 'create' : 'update'
            ));
            $onFormChanged('gravity_forms', $formId, [
                'event' => $isNew ? 'create' : 'update',
                'source_hook' => 'gform_after_save_form',
            ]);
        }, 20, 2);

        add_action('gform_after_delete_form', static function ($formId) use ($onFormChanged): void {
            $formId = trim((string) $formId);
            Debug::verbose(sprintf(
                'forms adapter event: gravity_forms hook=gform_after_delete_form form_id=%s event=delete',
                $formId
            ));
            if ($formId === '') {
                Debug::warn('forms adapter anomaly: gravity_forms hook=gform_after_delete_form reason=empty_form_id');
                return;
            }

            Debug::verbose(sprintf(
                'forms adapter dispatch: gravity_forms form_id=%s hook=gform_after_delete_form event=delete',
                $formId
            ));
            $onFormChanged('gravity_forms', $formId, [
                'event' => 'delete',
                'source_hook' => 'gform_after_delete_form',
            ]);
        }, 20, 1);
    }

    /**
     * Return shortcode tags.
     *
     * @return string[]
     */
    public function shortcodes(): array
    {
        return ['gravityform'];
    }

    /**
     * Return block names.
     *
     * @return string[]
     */
    public function blockNames(): array
    {
        return ['gravityforms/form'];
    }

    /**
     * Return candidate needles.
     *
     * @return string[]
     */
    public function candidateNeedles(): array
    {
        return ['gravityform', 'gravityforms/form'];
    }

    /**
     * Extract form IDs from text.
     *
     * @param string $text Source text.
     * @return string[]
     */
    public function extractFormIdsFromContent(string $text): array
    {
        if ($text === '') {
            return [];
        }

        $matches = [];

        if (preg_match_all('/\\[gravityform[^\]]*\\bid\\s*=\\s*["\']?([^"\'\]\s]+)["\']?/i', $text, $shortcodeMatches) > 0) {
            $matches = array_merge($matches, $shortcodeMatches[1] ?? []);
        }

        if (preg_match_all('/wp:gravityforms\\/form\\s+\{[^\}]*"formId"\\s*:\\s*"?([A-Za-z0-9_-]+)"?/i', $text, $blockMatches) > 0) {
            $matches = array_merge($matches, $blockMatches[1] ?? []);
        }

        return $this->normalizeIds($matches);
    }

}
