<?php
declare(strict_types=1);

namespace Ekesto\CacheInvalidator\Integrations\Forms\Adapters;

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

/**
 * Ninja Forms adapter.
 */
final class NinjaFormsAdapter implements FormAdapterInterface
{
    use NormalizesFormIds;

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

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

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

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

        $dispatch = static function ($formId, string $event, string $hook) use ($onFormChanged): void {
            $normalizedFormId = trim((string) $formId);
            Debug::verbose(sprintf(
                'forms adapter event: ninja_forms hook=%s form_id=%s event=%s',
                $hook,
                $normalizedFormId,
                $event
            ));
            if ($normalizedFormId === '') {
                return;
            }

            static $seen = [];
            $dedupeKey = $event . '|' . $normalizedFormId;
            if (isset($seen[$dedupeKey])) {
                Debug::verbose(sprintf(
                    'forms adapter skip: ninja_forms hook=%s form_id=%s reason=duplicate_event',
                    $hook,
                    $normalizedFormId
                ));
                return;
            }
            $seen[$dedupeKey] = true;

            $onFormChanged('ninja_forms', $normalizedFormId, [
                'event' => $event,
                'source_hook' => $hook,
            ]);
        };

        // Legacy Ninja Forms hook names.
        add_action('nf_create_form', static function ($formId) use ($dispatch): void {
            $dispatch($formId, 'create', 'nf_create_form');
        }, 20, 1);
        add_action('nf_save_form', static function ($formId) use ($dispatch): void {
            $dispatch($formId, 'update', 'nf_save_form');
        }, 20, 1);
        add_action('nf_delete_form', static function ($formId) use ($dispatch): void {
            $dispatch($formId, 'delete', 'nf_delete_form');
        }, 20, 1);

        // Ninja Forms v3+ action names.
        add_action('ninja_forms_save_form', static function ($formId) use ($dispatch): void {
            $dispatch($formId, 'update', 'ninja_forms_save_form');
        }, 20, 1);
        add_action('ninja_forms_after_save_form', static function ($formId) use ($dispatch): void {
            $dispatch($formId, 'update', 'ninja_forms_after_save_form');
        }, 20, 1);
        add_action('ninja_forms_delete_form', static function ($formId) use ($dispatch): void {
            $dispatch($formId, 'delete', 'ninja_forms_delete_form');
        }, 20, 1);
        add_action('ninja_forms_after_delete_form', static function ($formId) use ($dispatch): void {
            $dispatch($formId, 'delete', 'ninja_forms_after_delete_form');
        }, 20, 1);
    }

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

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

    /**
     * Return candidate needles.
     *
     * @return string[]
     */
    public function candidateNeedles(): array
    {
        return ['ninja_form', 'ninja-forms/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('/\\[ninja_form[^\]]*\\bid\\s*=\\s*["\']?([^"\'\]\s]+)["\']?/i', $text, $shortcodeMatches) > 0) {
            $matches = array_merge($matches, $shortcodeMatches[1] ?? []);
        }

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

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

}
