<?php

namespace ZenoChatbot\Support;

if (!defined('ABSPATH')) {
    exit;
}

/**
 * Central hook registry and two-phase dispatch facade.
 *
 * Every hook emitted by this plugin is defined here as a class constant.
 * The static methods delegate to HookDispatcher which runs first-party
 * listeners before broadcasting via standard WordPress hooks.
 *
 * Naming convention: DOMAIN_EVENT → 'zeno_chatbot_ai/{domain}/{event}'
 *
 * @see HOOKS.md for full reference with payload keys and examples.
 */
final class Hooks
{
    private static ?HookDispatcher $dispatcher = null;

    private function __construct() {}

    // ── Dispatch facade ──────────────────────────────────────────────────

    public static function dispatcher(): HookDispatcher
    {
        if (static::$dispatcher === null) {
            static::$dispatcher = new HookDispatcher();
        }

        return static::$dispatcher;
    }

    /**
     * Register a first-party action listener.
     */
    public static function addAction(string $hook, callable $listener, int $priority = 10): void
    {
        static::dispatcher()->on($hook, $listener, $priority);
    }

    /**
     * Register a first-party filter listener.
     */
    public static function addFilter(string $hook, callable $listener, int $priority = 10): void
    {
        static::dispatcher()->filter($hook, $listener, $priority);
    }

    /**
     * Dispatch an action: first-party listeners → WordPress broadcast.
     *
     * @param mixed $payload Single value or associative array for multi-value hooks
     */
    public static function doAction(string $hook, $payload): void
    {
        static::dispatcher()->dispatch($hook, $payload);
    }

    /**
     * Apply filters: first-party filters → WordPress broadcast.
     *
     * @param mixed $payload Single value or associative array for multi-value hooks
     * @return mixed The (potentially modified) payload
     */
    public static function applyFilters(string $hook, $payload)
    {
        return static::dispatcher()->apply($hook, $payload);
    }

    // ── Core ──────────────────────────────────────────────────────────────

    /** @action Fires when the free plugin is fully loaded. Payload: Application $app */
    public const CORE_LOADED = 'zeno_chatbot_ai/core/loaded';

    /** @action Fires before custom bindings are applied. Payload: Application $app */
    public const CORE_BINDINGS_LOADING = 'zeno_chatbot_ai/core/bindings_loading';

    /** @action Fires after custom bindings are applied. Payload: Application $app */
    public const CORE_BINDINGS_LOADED = 'zeno_chatbot_ai/core/bindings_loaded';

    /** @filter Filters route definitions before registration. Payload: array $routes */
    public const CORE_ROUTES = 'zeno_chatbot_ai/core/routes';

    // ── Chat ──────────────────────────────────────────────────────────────

    /** @filter Filters context array before LLM prompt assembly. Payload: [context*, message, conversation] */
    public const CHAT_CONTEXT = 'zeno_chatbot_ai/chat/context';

    /** @action Fires after a chat message is processed. Payload: [response, conversation, message] */
    public const CHAT_MESSAGE_PROCESSED = 'zeno_chatbot_ai/chat/message_processed';

    /** @action Fires after a new conversation is created. Payload: [conversation, user_context, source_data] */
    public const CHAT_CONVERSATION_CREATED = 'zeno_chatbot_ai/chat/conversation_created';

    /** @filter Filters the error response for a failed chat. Payload: array $response */
    public const CHAT_ERROR_RESPONSE = 'zeno_chatbot_ai/chat/error_response';

    // ── Conversation ─────────────────────────────────────────────────────

    /** @action Fires when a conversation status changes. Payload: [conversation, old_status, new_status] */
    public const CONVERSATION_STATUS_CHANGED = 'zeno_chatbot_ai/conversation/status_changed';

    /** @action Fires after an admin reply is sent. Payload: [conversation, message_id] */
    public const CONVERSATION_REPLY_SENT = 'zeno_chatbot_ai/conversation/reply_sent';

    /** @action Fires after a conversation is deleted. Payload: int $conversationId */
    public const CONVERSATION_DELETED = 'zeno_chatbot_ai/conversation/deleted';

    /** @action Fires when a conversation summary is requested. Payload: [conversation_id, trigger, requested_by, requested_at] */
    public const CONVERSATION_SUMMARY_REQUESTED = 'zeno_chatbot_ai/conversation/summary_requested';

    /** @action Fires after a summary is generated. Payload: [conversation_id, summary_message_id, status, generated_at, trigger] */
    public const CONVERSATION_SUMMARY_GENERATED = 'zeno_chatbot_ai/conversation/summary_generated';

    /** @action Fires when summary generation fails. Payload: [conversation_id, status, error_code, trigger, failed_at] */
    public const CONVERSATION_SUMMARY_FAILED = 'zeno_chatbot_ai/conversation/summary_failed';

    /** @action Scheduler job: processes a single conversation summary. */
    public const CONVERSATION_PROCESS_SUMMARY = 'zeno_chatbot_ai/conversation/process_summary';

    /** @action Scheduler job: runs conversation maintenance (auto-close, cleanup). */
    public const CONVERSATION_MAINTENANCE = 'zeno_chatbot_ai/conversation/maintenance';

    // ── Session ──────────────────────────────────────────────────────────

    /** @action Fires when a customer chat session ends. Payload: int $conversationId */
    public const SESSION_ENDED = 'zeno_chatbot_ai/session/ended';

    // ── Prompt ───────────────────────────────────────────────────────────

    /** @filter Filters the raw application instruction template. Payload: string $template */
    public const PROMPT_INSTRUCTION_TEMPLATE = 'zeno_chatbot_ai/prompt/instruction_template';

    /** @filter Filters the variables array for instruction template. Payload: array $variables */
    public const PROMPT_INSTRUCTION_VARIABLES = 'zeno_chatbot_ai/prompt/instruction_variables';

    /** @filter Filters the compiled application instruction. Payload: string $instruction */
    public const PROMPT_APPLICATION_INSTRUCTION = 'zeno_chatbot_ai/prompt/application_instruction';

    /** @filter Filters the system instruction. Payload: string $instruction */
    public const PROMPT_SYSTEM_INSTRUCTION = 'zeno_chatbot_ai/prompt/system_instruction';

    /** @filter Filters the additional instruction block. Payload: string $instruction */
    public const PROMPT_ADDITIONAL_INSTRUCTION = 'zeno_chatbot_ai/prompt/additional_instruction';

    /** @filter Filters the language instruction. Payload: [instruction*, language_code, language_info] */
    public const PROMPT_LANGUAGE_INSTRUCTION = 'zeno_chatbot_ai/prompt/language_instruction';

    // ── LLM ──────────────────────────────────────────────────────────────

    /** @filter Filters the list of enabled LLM providers. Payload: array $providers */
    public const LLM_PROVIDERS = 'zeno_chatbot_ai/llm/providers';

    /** @filter Filters the default LLM provider configuration. Payload: array $config */
    public const LLM_DEFAULT_PROVIDER = 'zeno_chatbot_ai/llm/default_provider';

    // ── Index ────────────────────────────────────────────────────────────

    /** @action Fires after internal content index is updated. Payload: [source, operation, timestamp, ...] */
    public const INDEX_INTERNAL_UPDATED = 'zeno_chatbot_ai/index/internal_updated';

    /** @action Fires after external sources index is updated. Payload: [source, operation, timestamp] */
    public const INDEX_EXTERNAL_UPDATED = 'zeno_chatbot_ai/index/external_updated';

    /** @action Fires after sitemap content index is updated. Payload: [source, operation, timestamp, ...] */
    public const INDEX_SITEMAP_UPDATED = 'zeno_chatbot_ai/index/sitemap_updated';

    /** @action Fires after product content index is updated. Payload: [source, operation, timestamp, ...] */
    public const INDEX_PRODUCT_UPDATED = 'zeno_chatbot_ai/index/product_updated';

    /** @action Fires after knowledge notes index is updated. Payload: [source, operation, timestamp] */
    public const INDEX_KNOWLEDGE_NOTES_UPDATED = 'zeno_chatbot_ai/index/knowledge_notes_updated';

    /** @action Scheduler job: async sitemap sync triggered by content changes. */
    public const INDEX_SITEMAP_SYNC = 'zeno_chatbot_ai/index/sitemap_sync';

    // ── Cache ────────────────────────────────────────────────────────────

    /** @filter Filters the resource text cache TTL in seconds. Payload: int $ttl */
    public const CACHE_RESOURCE_TTL = 'zeno_chatbot_ai/cache/resource_ttl';

    // ── Scheduler ────────────────────────────────────────────────────────

    /** @action Fires when a scheduled job fails. Payload: [job, reason, error?, payload, timestamp] */
    public const SCHEDULER_JOB_FAILED = 'zeno_chatbot_ai/scheduler/job_failed';

    /** @action Fires when a scheduled job completes. Payload: [job, timestamp] */
    public const SCHEDULER_JOB_PROCESSED = 'zeno_chatbot_ai/scheduler/job_processed';

    /** @action Scheduler job: periodic cleanup of completed/failed actions. */
    public const SCHEDULER_CLEANUP = 'zeno_chatbot_ai/scheduler/cleanup';

    // ── Settings ─────────────────────────────────────────────────────────

    /** @filter Filters extension data on the general settings page. Payload: array $extensions */
    public const SETTINGS_GENERAL_DATA = 'zeno_chatbot_ai/settings/general/data';

    /** @action Fires when general settings are saved. Payload: array $extensionData */
    public const SETTINGS_GENERAL_SAVE = 'zeno_chatbot_ai/settings/general/save';

    /** @filter Filters the countries list. Payload: array $countries */
    public const SETTINGS_COUNTRIES = 'zeno_chatbot_ai/settings/countries';

    // ── Admin ────────────────────────────────────────────────────────────

    /** @filter Filters registered extension nav/page declarations. Payload: array $extensions */
    public const ADMIN_EXTENSIONS = 'zeno_chatbot_ai/admin/extensions';

    /** @filter Filters registered extension script/style assets. Payload: array $scripts */
    public const ADMIN_EXTENSION_SCRIPTS = 'zeno_chatbot_ai/admin/extension_scripts';

    /** @filter Filters registered extension settings fields. Payload: array $fields */
    public const ADMIN_EXTENSION_FIELDS = 'zeno_chatbot_ai/admin/extension_fields';

    /** @filter Filters dashboard widget definitions. Payload: array $widgets */
    public const ADMIN_DASHBOARD_WIDGETS = 'zeno_chatbot_ai/admin/dashboard_widgets';

    /** @filter Whether the Pro extension is active. Payload: bool $isPro (default false) */
    public const ADMIN_IS_PRO = 'zeno_chatbot_ai/admin/is_pro';

    // ── Public ───────────────────────────────────────────────────────────

    /** @filter Filters the public chatbot widget configuration. Payload: array $config */
    public const PUBLIC_WIDGET_CONFIG = 'zeno_chatbot_ai/public/widget_config';
}
