<?php

namespace GriffinForms\Admin\Ajax;

class Forms extends \GriffinForms\Admin\Ajax\Format
{
    protected $response = [];
    protected $placement_service;
    protected const AI_AJAX_ACTIONS = [
        'initialize_ai_draft',
        'gf_ai_butler_broker',
        'gf_ai_apply_local_text_mutation',
        'publish_ai_draft',
        'discard_ai_draft',
        'undo_ai_draft',
        'reset_ai_draft',
    ];

    private function shouldRegisterAiHooks(): bool
    {
        if (!wp_doing_ajax()) {
            return false;
        }

        $action = isset($_REQUEST['action']) ? sanitize_key(wp_unslash($_REQUEST['action'])) : '';
        if ($action === '') {
            return false;
        }

        return in_array($action, self::AI_AJAX_ACTIONS, true);
    }

    private function formTableHasColumn(string $column): bool
    {
        global $wpdb;

        $table = $this->config->getTable('form');
        $exists = $wpdb->get_var($wpdb->prepare(
            "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = %s AND COLUMN_NAME = %s",
            $table,
            $column
        ));

        return !empty($exists);
    }

    private function isAiDraftForm(int $form_id): bool
    {
        if ($form_id <= 0 || !$this->sql->itemExists('form', $form_id)) {
            return false;
        }

        if ($this->formTableHasColumn('status')) {
            $status = (string) $this->sql->getItemValue($form_id, 'status', 'form');
            if ($status === 'draft') {
                return true;
            }
        }

        $origin = (string) $this->sql->getItemValue($form_id, 'origin', 'form');
        if ($origin === 'ai') {
            return true;
        }

        $integration_settings = $this->sql->getItemValue($form_id, 'integration_settings', 'form');
        $settings = $this->maybeDecode($integration_settings);

        return is_array($settings) && is_array($settings['ai_draft'] ?? null);
    }

    protected function setPlacementService()
    {
        $this->placement_service = \GriffinForms\Includes\Onboarding\PlacementService::getInstance();
    }

    private function consumeAiDraftAutoStartPrompt(int $form_id): void
    {
        $form_id = absint($form_id);
        if ($form_id <= 0) {
            return;
        }

        global $wpdb;
        $table = $this->config->getTable('form');
        $integration_settings = $this->sql->getItemValue($form_id, 'integration_settings', 'form');
        $settings = $this->maybeDecode($integration_settings);

        if (!is_array($settings) || !is_array($settings['ai_draft'] ?? null)) {
            return;
        }

        $settings['ai_draft']['auto_start_pending'] = 0;
        $settings['ai_draft']['last_requested_at'] = current_time('mysql', true);

        $wpdb->update(
            $table,
            ['integration_settings' => maybe_serialize($settings)],
            ['id' => $form_id],
            ['%s'],
            ['%d']
        );
    }

    /**
     * Seed a new blank form with minimum starter structure:
     * 1 page -> 1 row -> 1 full-width (12) column.
     */
    private function seedBlankFormStarterLayout(int $form_id): bool
    {
        $form_id = absint($form_id);
        if ($form_id <= 0) {
            return false;
        }

        $app_sql = \GriffinForms\Admin\Sql\App::getInstance();

        $page_id = $app_sql->createFormPage($form_id);
        if (!is_int($page_id) || $page_id <= 0) {
            return false;
        }

        $row_id = $app_sql->createPageRow($form_id);
        if (!is_int($row_id) || $row_id <= 0) {
            return false;
        }

        $page_rows_updated = $app_sql->updateFormPageRows($page_id, [absint($row_id)]);
        if ($page_rows_updated === false) {
            return false;
        }

        $form_pages_updated = $app_sql->updateFormFormPages($form_id, [absint($page_id)]);
        if ($form_pages_updated === false) {
            return false;
        }

        // Ensure row has at least one full-width column even if auto-attach fails.
        $row = $app_sql->itemValues($row_id, 'pagerow');
        $column_ids = is_object($row) ? $this->maybeDecode($row->rowcolumns) : [];
        if (!is_array($column_ids) || empty($column_ids)) {
            $column_id = $app_sql->createRowColumn(12, $form_id);
            if (!is_int($column_id) || $column_id <= 0) {
                return false;
            }

            $columns_updated = $app_sql->updatePageRowColumns($row_id, [absint($column_id)]);
            if ($columns_updated === false) {
                return false;
            }
        }

        return true;
    }

    public function exportForm() {
        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
        $nonce_status = wp_verify_nonce($nonce, 'export_form');
    
        if (!$nonce_status) {
            wp_send_json_error(__('Invalid nonce.', 'griffinforms-form-builder'));
            wp_die();
        }
    
        $form_id = isset($_POST['form_id']) ? absint(wp_unslash($_POST['form_id'])) : 0;
        if ($form_id) {
            $exporter = new \GriffinForms\Includes\ImportExport\FormExport($form_id);
            $form_data = $exporter->getFormData();
    
            if ($form_data) {
                echo wp_json_encode($form_data);
                wp_die();
            } else {
                wp_send_json_error(__('Form not found.', 'griffinforms-form-builder'));
            }
        } else {
            wp_send_json_error(__('Invalid Form ID.', 'griffinforms-form-builder'));
        }
    
        wp_die();
    }

    public function importForm() 
    {
        // Step 1: Retrieve and sanitize the nonce from POST data
        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
        // Step 2: Verify the nonce to prevent CSRF attacks
        $nonce_status = wp_verify_nonce($nonce, 'import_form');
    
        if (!$nonce_status) {
            // Nonce verification failed, return error response
            wp_send_json_error(__('Invalid nonce.', 'griffinforms-form-builder'));
            wp_die();
        }
    
        // Step 3: Check if JSON data is provided in the request
        if (isset($_POST['json_data'])) {
            // Step 4: Unslash the JSON data to normalize input
            $json_data = wp_unslash($_POST['json_data']);

            // Step 5: Validate that the input is an array
            if (!is_array($json_data)) {
                // Input format is invalid, return error response
                wp_send_json_error(__('The uploaded form file could not be read. Please make sure it is a valid GriffinForms export.', 'griffinforms-form-builder'));
                wp_die();
            }

            // Step 6: Ensure the input array is not empty
            if (empty($json_data)) {
                // Input data is empty, return error response
                wp_send_json_error(__('The uploaded file is empty. Please select a valid GriffinForms export.', 'griffinforms-form-builder'));
                wp_die();
            }

            // Step 7: Prevent overly large submissions by limiting array size
            if (count($json_data) > 1000) {
                // Input data exceeds allowed size, return error response
                wp_send_json_error(__('The uploaded form contains too many items. Please check the file or try a smaller export.', 'griffinforms-form-builder'));
                wp_die();
            }

            // Step 8: Recursively sanitize all values in the input array
            $sanitized_data = map_deep($json_data, 'sanitize_text_field');

            // Step 9: Initialize the form importer with sanitized data and perform import
            $importer = new \GriffinForms\Includes\ImportExport\FormImport($sanitized_data);
            $form_id = $importer->importForm();
            // Step 10: Return success response with the new form ID
            wp_send_json_success(['form_id' => $form_id]);
        } else {
            wp_send_json_error('Invalid request.');
        }
    
        wp_die();
    }

    public function createBlankForm() {
        check_ajax_referer('create_blank_form', 'nonce');
        $this->checkPostData('form_name');
        $form_name = sanitize_text_field(wp_unslash($_POST['form_name']));
        $starter_fields = isset($_POST['starter_fields']) ? wp_unslash($_POST['starter_fields']) : [];

        if (empty($form_name)) {
            wp_send_json_error(__('Form name is required.', 'griffinforms-form-builder'));
            wp_die();
        }

        if (!is_array($starter_fields)) {
            $starter_fields = [];
        }

        $starter_catalog = \GriffinForms\Includes\Onboarding\StarterCatalog::getInstance();
        $allowed_fields = array_keys($starter_catalog->getBlankFormStarterFieldOptions());
        $starter_fields = array_values(array_unique(array_filter(array_map('sanitize_key', $starter_fields), static function ($field_key) use ($allowed_fields) {
            return $field_key !== '' && in_array($field_key, $allowed_fields, true);
        })));

        $starter_generator = \GriffinForms\Includes\Onboarding\StarterGenerator::getInstance();
        $form_id = $starter_generator->createBlankFormWithStarterFields($form_name, '', $starter_fields);

        if (is_wp_error($form_id)) {
            wp_send_json_error($form_id->get_error_message());
            wp_die();
        }

        if (!$form_id) {
            wp_send_json_error(__('Failed to create form. Please try again.', 'griffinforms-form-builder'));
        }

        wp_send_json_success(['form_id' => $form_id]);
        wp_die();
    }

    public function searchSubmissionEditUsers()
    {
        check_ajax_referer('griffinforms_search_submission_edit_users', 'nonce');

        if (!current_user_can('manage_options') && !current_user_can('edit_posts')) {
            wp_send_json_error([
                'message' => __('You do not have permission to search users.', 'griffinforms-form-builder'),
            ], 403);
            wp_die();
        }

        $query = isset($_POST['query']) ? sanitize_text_field(wp_unslash($_POST['query'])) : '';
        if (mb_strlen($query) < 2) {
            wp_send_json_success(['users' => []]);
            wp_die();
        }

        $user_query = new \WP_User_Query([
            'search' => '*' . esc_attr($query) . '*',
            'search_columns' => ['user_login', 'user_email', 'display_name'],
            'number' => 20,
            'fields' => 'all',
            'orderby' => 'display_name',
            'order' => 'ASC',
        ]);

        $users = [];
        foreach ((array) $user_query->get_results() as $user) {
            if (!($user instanceof \WP_User)) {
                continue;
            }

            $users[] = [
                'id' => (int) $user->ID,
                'display_name' => $user->display_name !== '' ? $user->display_name : $user->user_login,
                'user_email' => $user->user_email,
            ];
        }

        wp_send_json_success([
            'users' => $users,
        ]);
        wp_die();
    }

    protected function normalizeFolderPickerFormIds($form_id = 0, $form_ids = [])
    {
        $ids = [];

        $single_form_id = absint($form_id);
        if ($single_form_id > 0) {
            $ids[] = $single_form_id;
        }

        if (is_array($form_ids)) {
            $ids = array_merge($ids, array_map('absint', $form_ids));
        } elseif (is_string($form_ids) && $form_ids !== '') {
            $decoded = json_decode($form_ids, true);
            if (is_array($decoded)) {
                $ids = array_merge($ids, array_map('absint', $decoded));
            }
        }

        return array_values(array_unique(array_filter($ids, static function ($id) {
            return $id > 0;
        })));
    }

    protected function getFolderPickerIconUrl(int $icon_key): string
    {
        $icon_key = max(1, absint($icon_key));
        return $this->config->getRootUrl() . 'admin/images/folder/' . $icon_key . '.png';
    }

    protected function updateFormsFolderAssignments(array $form_ids, int $folder_id)
    {
        global $wpdb;

        $form_ids = array_values(array_unique(array_filter(array_map('absint', $form_ids), static function ($id) {
            return $id > 0;
        })));

        if (empty($form_ids)) {
            return new \WP_Error('griffinforms_no_forms_selected', __('Please select at least one form first.', 'griffinforms-form-builder'), ['status' => 400]);
        }

        $form_table = $this->config->getTable('form');
        $folder_table = $this->config->getTable('folder');

        if ($folder_id > 0) {
            $folder_exists = (int) $wpdb->get_var(
                $wpdb->prepare("SELECT COUNT(*) FROM %i WHERE id = %d", $folder_table, $folder_id)
            );

            if ($folder_exists <= 0) {
                return new \WP_Error('griffinforms_folder_not_found', __('Target folder not found.', 'griffinforms-form-builder'), ['status' => 404]);
            }
        }

        $updated_count = 0;
        $untouched_count = 0;

        foreach ($form_ids as $form_id) {
            $form_row = $wpdb->get_row(
                $wpdb->prepare("SELECT id, folder FROM %i WHERE id = %d LIMIT 1", $form_table, $form_id),
                ARRAY_A
            );

            if (!is_array($form_row)) {
                return new \WP_Error('griffinforms_form_not_found', __('Form not found.', 'griffinforms-form-builder'), ['status' => 404, 'form_id' => $form_id]);
            }

            $current_folder_id = absint($form_row['folder'] ?? 0);
            if ($current_folder_id === $folder_id) {
                $untouched_count++;
                continue;
            }

            $updated = $wpdb->update(
                $form_table,
                ['folder' => $folder_id],
                ['id' => $form_id],
                ['%d'],
                ['%d']
            );

            if ($updated === false) {
                return new \WP_Error('griffinforms_folder_update_failed', __('Unable to update form folder.', 'griffinforms-form-builder'), ['status' => 500, 'form_id' => $form_id]);
            }

            $updated_count++;
        }

        return [
            'updated_count' => $updated_count,
            'untouched_count' => $untouched_count,
            'form_ids' => $form_ids,
            'folder_id' => $folder_id,
        ];
    }

    public function getFolderPickerFolders()
    {
        check_ajax_referer('griffinforms_folder_picker', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error([
                'message' => __('You do not have permission to update form folders.', 'griffinforms-form-builder'),
            ]);
            wp_die();
        }

        $search = isset($_POST['search']) ? sanitize_text_field(wp_unslash($_POST['search'])) : '';
        $offset = isset($_POST['offset']) ? absint(wp_unslash($_POST['offset'])) : 0;
        $limit = isset($_POST['limit']) ? absint(wp_unslash($_POST['limit'])) : 20;
        $limit = max(1, min($limit, 50));

        if ($search !== '' && mb_strlen($search) < 3) {
            wp_send_json_success([
                'folders' => [],
                'total' => 0,
                'has_more' => false,
                'search' => $search,
                'offset' => $offset,
                'limit' => $limit,
            ]);
            wp_die();
        }

        global $wpdb;
        $folder_table = $this->config->getTable('folder');

        $params = [$folder_table];
        $where_sql = '';
        if ($search !== '') {
            $search_like = '%' . $wpdb->esc_like($search) . '%';
            $where_sql = ' WHERE (name LIKE %s OR description LIKE %s)';
            $params[] = $search_like;
            $params[] = $search_like;
        }

        $count_sql = "SELECT COUNT(*) FROM %i" . $where_sql;
        $total = (int) $wpdb->get_var($wpdb->prepare($count_sql, ...$params));

        $list_params = $params;
        $list_sql = "SELECT id, name, description, icon FROM %i" . $where_sql . " ORDER BY name ASC, id ASC LIMIT %d OFFSET %d";
        $list_params[] = $limit;
        $list_params[] = $offset;
        $rows = $wpdb->get_results($wpdb->prepare($list_sql, ...$list_params), ARRAY_A);

        $folders = [];
        foreach ((array) $rows as $row) {
            $icon_key = absint($row['icon'] ?? 0);
            if ($icon_key <= 0) {
                $icon_key = 1;
            }

            $folders[] = [
                'id' => (int) ($row['id'] ?? 0),
                'name' => sanitize_text_field((string) ($row['name'] ?? '')),
                'description' => sanitize_textarea_field((string) ($row['description'] ?? '')),
                'icon' => (string) $icon_key,
                'icon_url' => $this->getFolderPickerIconUrl($icon_key),
            ];
        }

        wp_send_json_success([
            'folders' => $folders,
            'total' => $total,
            'has_more' => ($offset + count($folders)) < $total,
            'search' => $search,
            'offset' => $offset,
            'limit' => $limit,
            'message' => $search === ''
                ? __('Select a folder for the selected forms.', 'griffinforms-form-builder')
                : sprintf(
                    __('Search "%1$s" returned %2$d folders.', 'griffinforms-form-builder'),
                    $search,
                    $total
                ),
        ]);
        wp_die();
    }

    public function createFolderAndAssign()
    {
        check_ajax_referer('griffinforms_folder_picker', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error([
                'message' => __('You do not have permission to create folders.', 'griffinforms-form-builder'),
            ]);
            wp_die();
        }

        $name = sanitize_text_field((string) wp_unslash($_POST['name'] ?? ''));
        $description = sanitize_textarea_field((string) wp_unslash($_POST['description'] ?? ''));
        $icon_raw = sanitize_text_field((string) wp_unslash($_POST['icon'] ?? ''));
        $form_id = isset($_POST['form_id']) ? absint(wp_unslash($_POST['form_id'])) : 0;
        $form_ids = $this->normalizeFolderPickerFormIds($form_id, wp_unslash($_POST['form_ids'] ?? []));

        if ($name === '') {
            wp_send_json_error([
                'message' => __('Please enter folder name.', 'griffinforms-form-builder'),
            ]);
            wp_die();
        }

        if (empty($form_ids)) {
            wp_send_json_error([
                'message' => __('Please select at least one form first.', 'griffinforms-form-builder'),
            ]);
            wp_die();
        }

        $icon_key = absint(preg_replace('/[^0-9]/', '', $icon_raw));
        if ($icon_key <= 0) {
            $icon_key = 1;
        }

        $icon_url = $this->getFolderPickerIconUrl($icon_key);
        $icon_file = trailingslashit($this->config->getRootPath() . 'admin/images/folder') . $icon_key . '.png';
        if (!file_exists($icon_file)) {
            wp_send_json_error([
                'message' => __('Invalid folder icon.', 'griffinforms-form-builder'),
            ]);
            wp_die();
        }

        global $wpdb;
        $folder_table = $this->config->getTable('folder');
        $author = (string) get_current_user_id();
        $created = current_time('mysql', true);

        $inserted = $wpdb->insert(
            $folder_table,
            [
                'name' => $name,
                'heading' => $name,
                'description' => $description,
                'icon' => $icon_key,
                'author' => $author,
                'created' => $created,
                'last_editor' => $author,
                'last_edited' => $created,
            ],
            ['%s', '%s', '%s', '%d', '%s', '%s', '%s', '%s']
        );

        if ($inserted === false) {
            wp_send_json_error([
                'message' => __('Unable to create folder.', 'griffinforms-form-builder'),
            ]);
            wp_die();
        }

        $folder_id = (int) $wpdb->insert_id;
        $assignment = $this->updateFormsFolderAssignments($form_ids, $folder_id);
        if ($assignment instanceof \WP_Error) {
            $wpdb->delete($folder_table, ['id' => $folder_id], ['%d']);
            wp_send_json_error([
                'message' => $assignment->get_error_message(),
            ]);
            wp_die();
        }

        wp_send_json_success([
            'folder' => [
                'id' => $folder_id,
                'name' => $name,
                'description' => $description,
                'icon' => (string) $icon_key,
                'icon_url' => $icon_url,
            ],
            'updated_count' => (int) $assignment['updated_count'],
            'untouched_count' => (int) $assignment['untouched_count'],
            'form_ids' => $form_ids,
            'message' => __('Folder created and assigned.', 'griffinforms-form-builder'),
        ]);
        wp_die();
    }

    public function moveFormFolder()
    {
        check_ajax_referer('griffinforms_folder_picker', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error([
                'message' => __('You do not have permission to update form folders.', 'griffinforms-form-builder'),
            ]);
            wp_die();
        }

        $folder_id = isset($_POST['folder_id']) ? absint(wp_unslash($_POST['folder_id'])) : 0;
        $form_ids = $this->normalizeFolderPickerFormIds(
            isset($_POST['form_id']) ? absint(wp_unslash($_POST['form_id'])) : 0,
            wp_unslash($_POST['form_ids'] ?? [])
        );

        if (empty($form_ids)) {
            wp_send_json_error([
                'message' => __('Please select at least one form first.', 'griffinforms-form-builder'),
            ]);
            wp_die();
        }

        $assignment = $this->updateFormsFolderAssignments($form_ids, $folder_id);
        if ($assignment instanceof \WP_Error) {
            wp_send_json_error([
                'message' => $assignment->get_error_message(),
            ]);
            wp_die();
        }

        wp_send_json_success([
            'message' => (int) $assignment['updated_count'] > 1
                ? __('Folders updated successfully.', 'griffinforms-form-builder')
                : __('Folder updated successfully.', 'griffinforms-form-builder'),
            'folder_id' => $folder_id,
            'form_ids' => $form_ids,
            'updated_count' => (int) $assignment['updated_count'],
            'untouched_count' => (int) $assignment['untouched_count'],
        ]);
        wp_die();
    }

    public function placeForm()
    {
        check_ajax_referer('griffinforms_place_form', 'nonce');

        $form_id = isset($_POST['form_id']) ? absint(wp_unslash($_POST['form_id'])) : 0;
        $placement_action = isset($_POST['placement_action']) ? sanitize_key(wp_unslash($_POST['placement_action'])) : 'create_form_only';
        $placement_target_type = isset($_POST['placement_target_type']) ? sanitize_key(wp_unslash($_POST['placement_target_type'])) : 'page';
        $placement_target_id = isset($_POST['placement_target_id']) ? absint(wp_unslash($_POST['placement_target_id'])) : 0;
        $page_title = isset($_POST['page_title']) ? sanitize_text_field(wp_unslash($_POST['page_title'])) : '';

        $result = $this->placement_service->placeForm(
            $form_id,
            $placement_action,
            $placement_target_type,
            $placement_target_id,
            $page_title
        );

        if (is_wp_error($result)) {
            wp_send_json_error([
                'message' => $result->get_error_message(),
                'status' => $result->get_error_code(),
                'data' => $result->get_error_data(),
            ]);
            wp_die();
        }

        $message = __('Form placement completed.', 'griffinforms-form-builder');
        if (($result['action'] ?? '') === 'create_form_only') {
            $message = __('Shortcode copied and form is ready for manual placement.', 'griffinforms-form-builder');
        } elseif (!empty($result['post_id'])) {
            $message = __('Form published successfully.', 'griffinforms-form-builder');
        }

        wp_send_json_success([
            'message' => $message,
            'result' => $result,
            'shortcode' => $result['shortcode'] ?? '',
            'edit_url' => $result['edit_url'] ?? '',
            'view_url' => $result['view_url'] ?? '',
        ]);
        wp_die();
    }

    public function getFormPreviewUrl()
    {
        check_ajax_referer('griffinforms_get_form_preview_url', 'nonce');

        if (!current_user_can('edit_posts')) {
            wp_send_json_error([
                'message' => __('You do not have permission to preview forms.', 'griffinforms-form-builder'),
            ]);
            wp_die();
        }

        $form_id = isset($_POST['form_id']) ? absint(wp_unslash($_POST['form_id'])) : 0;
        if ($form_id < 1 || !$this->sql->itemExists('form', $form_id)) {
            wp_send_json_error([
                'message' => __('Form not found.', 'griffinforms-form-builder'),
            ]);
            wp_die();
        }

        $preview_page = \GriffinForms\Includes\Onboarding\PreviewPage::getInstance();
        $preview_url = $preview_page->getPreviewUrl($form_id);
        if ($preview_url === '') {
            wp_send_json_error([
                'message' => __('The preview page could not be prepared. Please try again.', 'griffinforms-form-builder'),
            ]);
            wp_die();
        }

        wp_send_json_success([
            'preview_url' => $preview_url,
            'preview_page_id' => $preview_page->ensurePage(),
        ]);
        wp_die();
    }

    public function initialize_ai_draft() {
        check_ajax_referer('initialize_ai_draft', 'nonce');

        $ai_availability = new \GriffinForms\Includes\Ai\AiAvailabilityState();
        $can_proceed = $ai_availability->isActive() || !empty($ai_availability->getAvailableConnectorProviders());
        if (!$can_proceed) {
            $provider_mapped = $ai_availability->isProviderMapped();
            wp_send_json_error([
                'message' => $provider_mapped
                    ? __('Griffin Assist is missing an API key. Configure it in Settings before starting an AI draft.', 'griffinforms-form-builder')
                    : __('Griffin Assist does not have an AI provider selected. Configure it in Settings before starting an AI draft.', 'griffinforms-form-builder'),
                'status' => $provider_mapped ? 'ai_key_missing' : 'ai_provider_missing',
            ]);
            wp_die();
        }
        
        $prompt = isset($_POST['prompt']) ? sanitize_textarea_field(wp_unslash($_POST['prompt'])) : '';
        $form_name = !empty($prompt) ? $this->deriveFormNameFromPrompt($prompt) : __('AI Draft Form', 'griffinforms-form-builder');
        
        $item_type = 'form';
        $item_data = [
            'name' => $form_name,
            'heading' => $form_name,
            'description' => '',
            'folder' => 0,
            'autofill' => 0,
            'limit_entries' => maybe_serialize([]),
            'availability_window' => maybe_serialize([]),
            'lifetime_submission_count' => 0,
            'access_level' => maybe_serialize([]),
            'submission_edit' => maybe_serialize([]),
            'user_action' => maybe_serialize([]),
            'alert_emails' => maybe_serialize([]),
            'save_entries' => '',
            'autoresponder' => 0,
            'integration_settings' => maybe_serialize([
                'ai_draft' => [
                    'prompt' => $prompt,
                    'created_at' => current_time('mysql', true),
                    'session_id' => wp_generate_uuid4(),
                    'auto_start_pending' => 1,
                ]
            ]),
            'formpages' => maybe_serialize([]),
            'origin' => 'ai',
            'author' => get_current_user_id(),
            'created' => current_time('mysql', true)
        ];
        if ($this->formTableHasColumn('status')) {
            $item_data['status'] = 'draft';
        }
        $format = [
            '%s', // name
            '%s', // heading
            '%s', // description
            '%d', // folder
            '%d', // autofill
            '%s', // limit_entries
            '%s', // availability_window
            '%d', // lifetime_submission_count
            '%s', // access_level
            '%s', // submission_edit
            '%s', // user_action
            '%s', // alert_emails
            '%s', // save_entries
            '%d', // autoresponder
            '%s', // integration_settings
            '%s', // formpages
            '%s', // origin
            '%d', // author
            '%s', // created
        ];
        if ($this->formTableHasColumn('status')) {
            $format[] = '%s'; // status
        }
    
        $form_id = $this->sql->createFormElement($item_type, $item_data, $format);
    
        if ($form_id) {
            $seeded = $this->seedBlankFormStarterLayout((int) $form_id);
            if (!$seeded) {
                $this->sql->deleteForm((int) $form_id, false);
                wp_send_json_error(__('Failed to initialize AI draft layout.', 'griffinforms-form-builder'));
                wp_die();
            }

            $redirect_url = admin_url('admin.php?page=griffinforms-app&form_id=' . $form_id . '&mode=ai_draft');
            wp_send_json_success([
                'form_id' => $form_id,
                'redirect_url' => $redirect_url,
                'prompt' => $prompt
            ]);
        } else {
            wp_send_json_error(__('Failed to create AI draft. Please try again.', 'griffinforms-form-builder'));
        }
        wp_die();
    }

    public function processButlerPrompt()
    {
        set_time_limit(120);
        check_ajax_referer('initialize_ai_draft', 'nonce');

        $prompt = isset($_POST['prompt']) ? sanitize_textarea_field(wp_unslash($_POST['prompt'])) : '';
        $form_id = isset($_POST['form_id']) ? absint(wp_unslash($_POST['form_id'])) : 0;
        $selected_context = isset($_POST['selected_context']) ? wp_unslash($_POST['selected_context']) : '';
        $selected_context = is_string($selected_context) && $selected_context !== '' ? json_decode($selected_context, true) : [];
        $request_context = isset($_POST['request_context']) ? wp_unslash($_POST['request_context']) : '';
        $request_context = is_string($request_context) && $request_context !== '' ? json_decode($request_context, true) : [];

        if ($form_id <= 0 || !$this->sql->itemExists('form', $form_id)) {
            wp_send_json_error([
                'message' => __('The selected draft could not be found.', 'griffinforms-form-builder'),
                'status' => 'invalid_form',
                'mutated_ids' => [],
            ]);
            wp_die();
        }

        $this->consumeAiDraftAutoStartPrompt($form_id);
        $snapshot_manager = new \GriffinForms\Includes\Ai\Aidraftsnapshotmanager();
        $snapshot_manager->ensureBaselineSnapshotForCurrentState($form_id);
        $pre_action_snapshot = $snapshot_manager->capturePreActionSnapshot($form_id);

        $router = new \GriffinForms\Includes\Ai\SurfaceRouter();
        $result = $router->route(
            $form_id,
            $prompt,
            is_array($selected_context) ? $selected_context : [],
            is_array($request_context) ? $request_context : []
        );

        if (!empty($result['success'])) {
            if (is_array($pre_action_snapshot)) {
                $snapshot_manager->storePreActionSnapshot($form_id, $pre_action_snapshot);
            }
            wp_send_json_success($result);
        } else {
            wp_send_json_error($result);
        }

        wp_die();
    }

    public function applyLocalTextMutation()
    {
        check_ajax_referer('initialize_ai_draft', 'nonce');

        $form_id = isset($_POST['form_id']) ? absint(wp_unslash($_POST['form_id'])) : 0;
        $property = isset($_POST['target_property']) ? sanitize_key(wp_unslash($_POST['target_property'])) : '';
        $value = isset($_POST['value']) ? sanitize_text_field(wp_unslash($_POST['value'])) : '';
        $source_prompt = isset($_POST['source_prompt']) ? sanitize_textarea_field(wp_unslash($_POST['source_prompt'])) : '';
        $selected_context = isset($_POST['selected_context']) ? wp_unslash($_POST['selected_context']) : '';
        $selected_context = is_string($selected_context) && $selected_context !== '' ? json_decode($selected_context, true) : [];

        if ($form_id <= 0 || !$this->sql->itemExists('form', $form_id)) {
            wp_send_json_error([
                'message' => __('The selected draft could not be found.', 'griffinforms-form-builder'),
                'status' => 'invalid_form',
                'mutated_ids' => [],
            ]);
            wp_die();
        }

        $applier = new \GriffinForms\Includes\Ai\LocalTextMutationApplier();
        $result = $applier->apply(
            $form_id,
            is_array($selected_context) ? $selected_context : [],
            $property,
            $value,
            $source_prompt !== '' ? $source_prompt : sprintf('Local text mutation: %s', $property)
        );

        if (!empty($result['success'])) {
            $result['status'] = 'applied';
            $result['message'] = $source_prompt !== '' ? __('Applied your selected text change.', 'griffinforms-form-builder') : __('Text updated successfully.', 'griffinforms-form-builder');
            $result['is_new'] = true;
            wp_send_json_success($result);
        }

        wp_send_json_error([
            'message' => (string) ($result['message'] ?? __('Griffin Assist could not apply that local text update.', 'griffinforms-form-builder')),
            'status' => 'local_text_apply_failed',
            'mutated_ids' => [],
        ]);
        wp_die();
    }

    public function resolvePathToken(): void
    {
        set_time_limit(120);
        check_ajax_referer('initialize_ai_draft', 'nonce');

        $form_id    = isset($_POST['form_id']) ? absint(wp_unslash($_POST['form_id'])) : 0;
        $path_token = isset($_POST['path_token']) ? sanitize_text_field(wp_unslash($_POST['path_token'])) : '';
        $selected_context = isset($_POST['selected_context']) ? wp_unslash($_POST['selected_context']) : '';
        $selected_context = is_string($selected_context) && $selected_context !== '' ? json_decode($selected_context, true) : [];

        if ($form_id <= 0 || !$this->sql->itemExists('form', $form_id)) {
            wp_send_json_error([
                'message' => __('The selected draft could not be found.', 'griffinforms-form-builder'),
                'status'  => 'invalid_form',
                'mutated_ids' => [],
            ]);
            wp_die();
        }

        $user_id       = (int) get_current_user_id();
        $transient_key = "gf_assist_paths_{$user_id}_{$form_id}_{$path_token}";
        $stored        = get_transient($transient_key);

        if ($stored === false || !is_array($stored)) {
            wp_send_json_error([
                'message' => __("That option has expired. Please send your message again and I'll suggest new options.", 'griffinforms-form-builder'),
                'status'  => 'token_expired',
                'mutated_ids' => [],
            ]);
            wp_die();
        }

        delete_transient($transient_key);

        $handler_key = sanitize_key((string) ($stored['handler_key'] ?? ''));
        if ($handler_key === '' || $handler_key === 'unsupported') {
            wp_send_json_error([
                'message' => __("Griffin Assist couldn't process that request.", 'griffinforms-form-builder'),
                'status'  => 'unsupported',
                'mutated_ids' => [],
            ]);
            wp_die();
        }

        $snapshot_manager = new \GriffinForms\Includes\Ai\Aidraftsnapshotmanager();
        $snapshot_manager->ensureBaselineSnapshotForCurrentState($form_id);
        $pre_action_snapshot = $snapshot_manager->capturePreActionSnapshot($form_id);

        $router = new \GriffinForms\Includes\Ai\BuilderAssistRouter();
        $request_context = [
            'surface'         => 'form_builder',
            'response_family' => 'mutation',
            'response_mode'   => 'patch_required',
        ];

        $result = $router->executeResolved(
            $form_id,
            $handler_key,
            is_array($selected_context) ? $selected_context : [],
            $request_context
        );

        if (!empty($result['success'])) {
            if (is_array($pre_action_snapshot)) {
                $snapshot_manager->storePreActionSnapshot($form_id, $pre_action_snapshot);
            }
            wp_send_json_success($result);
        } else {
            wp_send_json_error($result);
        }

        wp_die();
    }

    private function userCanManageDraft(int $form_id): bool
    {
        if ($form_id <= 0 || !$this->sql->itemExists('form', $form_id)) {
            return false;
        }

        if (current_user_can('manage_options')) {
            return true;
        }

        $author_id = (int) $this->sql->getItemValue($form_id, 'author', 'form');
        return $author_id > 0 && $author_id === (int) get_current_user_id();
    }

    private function markAiDraftResolved(int $form_id, string $resolution): void
    {
        global $wpdb;

        $table = $this->config->getTable('form');
        $integration_settings = $this->sql->getItemValue($form_id, 'integration_settings', 'form');
        $settings = $this->maybeDecode($integration_settings);

        if (!is_array($settings)) {
            $settings = [];
        }

        $settings['ai_draft'] = array_merge(
            (array) ($settings['ai_draft'] ?? []),
            [
                'auto_start_pending' => 0,
                'resolved_at' => current_time('mysql', true),
                'resolution' => sanitize_key($resolution),
            ]
        );

        $wpdb->update(
            $table,
            ['integration_settings' => maybe_serialize($settings)],
            ['id' => $form_id],
            ['%s'],
            ['%d']
        );
    }

    public function publishAiDraft()
    {
        check_ajax_referer('publish_ai_draft', 'nonce');

        $form_id = isset($_POST['form_id']) ? absint(wp_unslash($_POST['form_id'])) : 0;
        if (!$this->userCanManageDraft($form_id)) {
            wp_send_json_error([
                'message' => __('You are not allowed to publish this AI draft.', 'griffinforms-form-builder'),
                'status' => 'forbidden',
            ]);
            wp_die();
        }

        if (!$this->isAiDraftForm($form_id)) {
            wp_send_json_error([
                'message' => __('This form does not have an active AI draft session. Please reload and try again.', 'griffinforms-form-builder'),
                'status' => 'invalid_state',
            ]);
            wp_die();
        }

        $update_data = [
            'origin' => 'local',
            'last_editor' => get_current_user_id(),
            'last_edited' => current_time('mysql', true),
        ];
        if ($this->formTableHasColumn('status')) {
            $update_data['status'] = 'published';
        }

        $updated = $this->sql->updateData($update_data, ['id' => $form_id]);

        if ($updated === false) {
            wp_send_json_error([
                'message' => __('Failed to publish the AI draft. Please try again.', 'griffinforms-form-builder'),
                'status' => 'publish_failed',
            ]);
            wp_die();
        }

        $this->markAiDraftResolved($form_id, 'published');
        $this->log->add('info', 'ai_draft', $form_id, (int) get_current_user_id(), 'AI draft published into canonical form workflow.', 'ai_draft_publish');

        wp_send_json_success([
            'message' => __('Draft published. Opening the standard builder view...', 'griffinforms-form-builder'),
            'redirect_url' => admin_url('admin.php?page=griffinforms-app&form_id=' . $form_id),
        ]);
        wp_die();
    }

    public function discardAiDraft()
    {
        check_ajax_referer('discard_ai_draft', 'nonce');

        $form_id = isset($_POST['form_id']) ? absint(wp_unslash($_POST['form_id'])) : 0;
        if (!$this->userCanManageDraft($form_id)) {
            wp_send_json_error([
                'message' => __('You are not allowed to discard this AI draft.', 'griffinforms-form-builder'),
                'status' => 'forbidden',
            ]);
            wp_die();
        }

        if (!$this->isAiDraftForm($form_id)) {
            wp_send_json_error([
                'message' => __('This form does not have an active AI draft session. Please reload and try again.', 'griffinforms-form-builder'),
                'status' => 'invalid_state',
            ]);
            wp_die();
        }

        $this->markAiDraftResolved($form_id, 'discarded');

        // Forms created by the AI flow (origin='ai') are temporary — delete on discard.
        // Forms opened via "AI Edit" (origin!='ai') are real forms — just exit the AI view.
        $origin = (string) $this->sql->getItemValue($form_id, 'origin', 'form');
        if ($origin === 'ai') {
            $deleted = $this->sql->deleteForm($form_id, false);

            if (!$deleted) {
                wp_send_json_error([
                    'message' => __('Failed to discard the AI draft. Please try again.', 'griffinforms-form-builder'),
                    'status' => 'discard_failed',
                ]);
                wp_die();
            }

            $this->log->add('info', 'ai_draft', $form_id, (int) get_current_user_id(), 'AI draft discarded and deleted.', 'ai_draft_discard');
        } else {
            $this->log->add('info', 'ai_draft', $form_id, (int) get_current_user_id(), 'AI edit session discarded (form preserved).', 'ai_draft_discard');
        }

        wp_send_json_success([
            'message' => __('Returning to your forms list...', 'griffinforms-form-builder'),
            'redirect_url' => admin_url('admin.php?page=griffinforms-forms'),
        ]);
        wp_die();
    }

    public function undoAiDraft()
    {
        check_ajax_referer('undo_ai_draft', 'nonce');

        $form_id = isset($_POST['form_id']) ? absint(wp_unslash($_POST['form_id'])) : 0;
        if (!$this->userCanManageDraft($form_id)) {
            wp_send_json_error([
                'message' => __('You are not allowed to modify this AI draft.', 'griffinforms-form-builder'),
                'status' => 'forbidden',
            ]);
            wp_die();
        }

        if (!$this->isAiDraftForm($form_id)) {
            wp_send_json_error([
                'message' => __('This form is no longer in AI draft mode.', 'griffinforms-form-builder'),
                'status' => 'invalid_state',
            ]);
            wp_die();
        }

        $result = (new \GriffinForms\Includes\Ai\Aidraftsnapshotmanager())->undoLastAction($form_id);
        if (!empty($result['success'])) {
            wp_send_json_success($result);
        }

        wp_send_json_error($result);
        wp_die();
    }

    public function resetAiDraft()
    {
        check_ajax_referer('reset_ai_draft', 'nonce');

        $form_id = isset($_POST['form_id']) ? absint(wp_unslash($_POST['form_id'])) : 0;
        if (!$this->userCanManageDraft($form_id)) {
            wp_send_json_error([
                'message' => __('You are not allowed to modify this AI draft.', 'griffinforms-form-builder'),
                'status' => 'forbidden',
            ]);
            wp_die();
        }

        if (!$this->isAiDraftForm($form_id)) {
            wp_send_json_error([
                'message' => __('This form is no longer in AI draft mode.', 'griffinforms-form-builder'),
                'status' => 'invalid_state',
            ]);
            wp_die();
        }

        $result = (new \GriffinForms\Includes\Ai\Aidraftsnapshotmanager())->resetToBaseline($form_id);
        if (!empty($result['success'])) {
            wp_send_json_success($result);
        }

        wp_send_json_error($result);
        wp_die();
    }

    public function createFormFromTemplate()
    {
        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
        $nonce_status = wp_verify_nonce($nonce, 'form_from_template');
    
        if (!$nonce_status) {
            wp_send_json_error(__('Invalid nonce.', 'griffinforms-form-builder'));
            wp_die();
        }
 
        $this->checkPostData('template_id');
        $template_id = absint(wp_unslash($_POST['template_id']));

        if (!$this->sql->itemExists('template', $template_id)) {
            wp_send_json_error(__('Selected template no longer exists.', 'griffinforms-form-builder'));
            wp_die();
        }

        $form_data = $this->sql->getItemValue($template_id, 'form_data', 'template');

        if (!$form_data) {
            wp_send_json_error(__('Template not found or invalid form data.', 'griffinforms-form-builder'));
        }

        $form_data_array = $this->maybeDecode($form_data);

        if (!is_array($form_data_array)) {
            wp_send_json_error(__('Invalid form JSON data.', 'griffinforms-form-builder'));
        }

        $form_import = new \GriffinForms\Includes\ImportExport\FormImport($form_data_array);        
        $result = $form_import->importForm(is_template: true);

        if ($result) {
            wp_send_json_success($result);
        } else {
            wp_send_json_error(__('Form import failed.', 'griffinforms-form-builder'));
        }

        wp_die();
    }

    public function getFormTemplates() {
        // Verify nonce
        check_ajax_referer('get_form_templates', 'nonce');
    
        // Get category and pagination parameters
        $category = isset($_POST['category']) ? sanitize_text_field(wp_unslash($_POST['category'])) : 'All';
        $offset = isset($_POST['offset']) ? absint(wp_unslash($_POST['offset'])) : 0;
        $limit = isset($_POST['limit']) ? absint(wp_unslash($_POST['limit'])) : 10;
    
        // Fetch templates with offset and limit
        $templates = $this->sql->getFormTemplates($category, '', $offset, $limit);

        if (empty($templates)) {
            wp_send_json_error([
                'message' => __('😕 Sorry, no more templates in this category.', 'griffinforms-form-builder'),
                'empty' => true
            ]);
        } else {
            $template_html = new \GriffinForms\Admin\Html\Elements\TemplateCard();
            $html = $template_html->cardsHtml($templates); // Generate HTML for templates
            wp_send_json_success($html); // Send response back to AJAX
        }

        wp_die();
    }

    public function uploadTemplate() {
        check_ajax_referer('upload_template', 'nonce');
    
        // Sanitize and validate template data
        $template_name = isset($_POST['template_name']) ? sanitize_text_field(wp_unslash($_POST['template_name'])) : '';
        $template_description = isset($_POST['template_description']) ? sanitize_textarea_field(wp_unslash($_POST['template_description'])) : '';
        $template_category = isset($_POST['template_category']) ? sanitize_text_field(wp_unslash($_POST['template_category'])) : '';
        $form_data = isset($_POST['form_data']) ? wp_unslash($_POST['form_data']) : null;
    
        // Check for required fields
        if (empty($template_name) || empty($form_data)) {
            wp_send_json_error(__('Template name and JSON data are required.', 'griffinforms-form-builder'));
            wp_die();
        }

    
        // Validate JSON structure
        if (!is_array($form_data) || !isset($form_data)) {
            wp_send_json_error(__('Invalid JSON structure for form data.', 'griffinforms-form-builder'));
            wp_die();
        }
    
        // Prepare data for SQL insertion
        $template_data = [
            'name' => $template_name,
            'description' => $template_description,
            'category' => $template_category,
            'tags' => $json_data['tags'] ?? [],
            'form_data' => $form_data,
            'origin' => 'user'
        ];
    
        // Insert template using the SQL class method
        $template_id = $this->sql->insertTemplate($template_data);
    
        if ($template_id) {
            wp_send_json_success([
                'message' => __('Template uploaded successfully!', 'griffinforms-form-builder'),
                'template_id' => $template_id
            ]);
        } else {
            wp_send_json_error(__('Failed to upload template. Please try again.', 'griffinforms-form-builder'));
        }
    
        wp_die();
    }
    
    public function searchTemplates() {

        check_ajax_referer('search_templates', 'nonce');

        $search_term = isset($_POST['search_term']) ? sanitize_text_field(wp_unslash($_POST['search_term'])) : '';
        
        if (empty($search_term)) {
            wp_send_json_error(__('Search keyword is required.', 'griffinforms-form-builder'));
            wp_die();
        }

        $templates = $this->sql->getFormTemplatesBySearch($search_term);
        $template_count = count($templates);

        $template_html = new \GriffinForms\Admin\Html\Elements\TemplateCard(category: '', search_term: $search_term);
        $html = $template_html->cardsHtml($templates);
        wp_send_json_success([
            'html' => $html,
            'count' => $template_count
        ]);
        wp_die();
    }

    // Preview AJAX endpoints removed: previews are rendered with template cards

    public function deleteForms()
    {
        // Check nonce for security
        check_ajax_referer('delete_forms', 'nonce');
    
        // Get form IDs and delete submissions option
        $form_ids = isset($_POST['form_ids']) && is_array($_POST['form_ids']) ? array_map('intval', wp_unslash($_POST['form_ids'])) : [];
        $delete_submissions = isset($_POST['delete_submissions']) ? (bool) $_POST['delete_submissions'] : false;
    
        // Verify that form IDs are provided
        if (empty($form_ids)) {
            wp_send_json_error(__('No forms selected for deletion.', 'griffinforms-form-builder'));
        }
    
        // Initialize a success flag and a message log
        $success = true;
        $message_log = [];
    
        // Iterate through form IDs and delete each one
        foreach ($form_ids as $form_id) {
            if ($this->sql->deleteForm($form_id)) {
                /* translators: %d is the ID of the deleted form */
                $message_log[] = sprintf(__('Form ID %d deleted successfully.', 'griffinforms-form-builder'), $form_id);
    
                // If delete submissions is enabled, delete associated submissions
                if ($delete_submissions) {
                    if ($this->sql->deleteSubmissionsByFormId($form_id)) {
                        /* translators: %d is the ID of the form whose submissions were deleted */
                        $message_log[] = sprintf(__('Associated submissions for Form ID %d deleted.', 'griffinforms-form-builder'), $form_id);
                    } else {
                        /* translators: %d is the ID of the form whose submissions could not be deleted */
                        $message_log[] = sprintf(__('Failed to delete submissions for Form ID %d.', 'griffinforms-form-builder'), $form_id);
                        $success = false;
                    }
                }
            } else {
                /* translators: %d is the ID of the form that could not be deleted */
                $message_log[] = sprintf(__('Failed to delete Form ID %d.', 'griffinforms-form-builder'), $form_id);
                $success = false;
            }
        }
    
        if ($success) {
            wp_send_json_success(['message_log' => $message_log]);
        } else {
            wp_send_json_error(['message_log' => $message_log]);
        }
    }

    public function runRetentionCleanup()
    {
        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
        if (!wp_verify_nonce($nonce, 'run_retention_cleanup')) {
            wp_send_json_error(['message' => __('Invalid nonce.', 'griffinforms-form-builder')]);
            wp_die();
        }

        $form_id = isset($_POST['form_id']) ? absint(wp_unslash($_POST['form_id'])) : 0;
        if (!$form_id) {
            wp_send_json_error(['message' => __('Invalid form ID.', 'griffinforms-form-builder')]);
            wp_die();
        }

        $result = \GriffinForms\Includes\Schedulers\SubmissionRetentionCleanup::getInstance()->runForForm($form_id);
        wp_send_json_success($result);
    }

    public function resetLifetimeSubmissionCount()
    {
        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => __('Permission denied.', 'griffinforms-form-builder')]);
            wp_die();
        }

        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
        if (!wp_verify_nonce($nonce, 'reset_lifetime_submission_count')) {
            wp_send_json_error(['message' => __('Invalid nonce.', 'griffinforms-form-builder')]);
            wp_die();
        }

        $form_id = isset($_POST['form_id']) ? absint(wp_unslash($_POST['form_id'])) : 0;
        if (!$form_id) {
            wp_send_json_error(['message' => __('Invalid form ID.', 'griffinforms-form-builder')]);
            wp_die();
        }

        global $wpdb;
        $table = $this->config->getTable('form');
        $updated = $wpdb->update(
            $table,
            ['lifetime_submission_count' => 0],
            ['id' => $form_id],
            ['%d'],
            ['%d']
        );

        if ($updated === false) {
            wp_send_json_error(['message' => __('Failed to reset lifetime count.', 'griffinforms-form-builder')]);
            wp_die();
        }

        wp_send_json_success(['count' => 0]);
    }
    
    public function translate_form()
    {
        check_ajax_referer('initialize_ai_draft', 'nonce');

        $form_id = isset($_POST['form_id']) ? absint(wp_unslash($_POST['form_id'])) : 0;
        $target_language = isset($_POST['target_language']) ? sanitize_text_field(wp_unslash($_POST['target_language'])) : '';

        if ($form_id <= 0 || !$this->sql->itemExists('form', $form_id)) {
            wp_send_json_error([
                'message' => __('The selected draft could not be found.', 'griffinforms-form-builder'),
                'status' => 'invalid_form',
            ]);
            wp_die();
        }

        if ($target_language === '') {
            $target_language = (string) get_bloginfo('language');
        }

        $prompt = sprintf('Translate the entire form into %s. This includes form name, description, all page/row copy, field labels, placeholders, and choice options.', $target_language);
        
        $router = new \GriffinForms\Includes\Ai\SurfaceRouter();
        $result = $router->route(
            $form_id,
            $prompt,
            ['item_type' => 'form', 'item_id' => $form_id],
            [
                'semantic_intent' => 'builder_bulk_text',
                'origin' => 'ui_button',
            ]
        );

        if (!empty($result['success'])) {
            wp_send_json_success($result);
        } else {
            wp_send_json_error($result);
        }

        wp_die();
    }
    
    private function deriveFormNameFromPrompt(string $prompt): string
    {
        $clean = trim($prompt);

        // Strip leading imperative verbs ("create a", "build me a", "make an", "i need a", "generate a", etc.)
        $clean = preg_replace(
            '/^(?:please\s+)?(?:create|build|make|generate|draft|design|write|set\s+up|i\s+need|i\s+want|give\s+me)\s+(?:me\s+)?(?:a\s+|an\s+|the\s+)?/i',
            '',
            $clean
        );

        $clean = trim($clean);

        if ($clean === '') {
            return __('AI Draft Form', 'griffinforms-form-builder');
        }

        // Title-case the first letter, truncate at 60 chars
        $name = mb_strtoupper(mb_substr($clean, 0, 1)) . mb_substr($clean, 1);
        if (mb_strlen($name) > 60) {
            $name = mb_substr($name, 0, 57) . '…';
        }

        return $name;
    }

    public function __construct()
    {
        $this->setAll();
        add_action('wp_ajax_exportForm', array($this, 'exportForm'));
        add_action('wp_ajax_importForm', array($this, 'importForm'));
        add_action('wp_ajax_createFormFromTemplate', array($this, 'createFormFromTemplate'));
        add_action('wp_ajax_getFormTemplates', array($this, 'getFormTemplates'));
        add_action('wp_ajax_griffinforms_search_submission_edit_users', array($this, 'searchSubmissionEditUsers'));
        add_action('wp_ajax_createBlankForm', [$this, 'createBlankForm']);
        add_action('wp_ajax_uploadTemplate', [$this, 'uploadTemplate']);
        add_action('wp_ajax_searchTemplates', [$this, 'searchTemplates']);
        add_action('wp_ajax_griffinforms_place_form', [$this, 'placeForm']);
        add_action('wp_ajax_griffinforms_get_form_preview_url', [$this, 'getFormPreviewUrl']);
        add_action('wp_ajax_griffinforms_get_folder_picker_folders', [$this, 'getFolderPickerFolders']);
        add_action('wp_ajax_griffinforms_create_folder_and_assign', [$this, 'createFolderAndAssign']);
        add_action('wp_ajax_griffinforms_move_form_folder', [$this, 'moveFormFolder']);
        // Removed preview fetch endpoints (server renders previews in cards)
        add_action('wp_ajax_deleteForms', [$this, 'deleteForms']);
        add_action('wp_ajax_griffinforms_run_retention_cleanup', [$this, 'runRetentionCleanup']);
        add_action('wp_ajax_griffinforms_reset_lifetime_submission_count', [$this, 'resetLifetimeSubmissionCount']);

        if ($this->shouldRegisterAiHooks()) {
            add_action('wp_ajax_initialize_ai_draft', [$this, 'initialize_ai_draft']);
            add_action('wp_ajax_gf_ai_butler_broker', [$this, 'processButlerPrompt']);
            add_action('wp_ajax_gf_ai_apply_local_text_mutation', [$this, 'applyLocalTextMutation']);
            add_action('wp_ajax_publish_ai_draft', [$this, 'publishAiDraft']);
            add_action('wp_ajax_discard_ai_draft', [$this, 'discardAiDraft']);
            add_action('wp_ajax_undo_ai_draft', [$this, 'undoAiDraft']);
            add_action('wp_ajax_reset_ai_draft', [$this, 'resetAiDraft']);
            add_action('wp_ajax_translate_form', [$this, 'translate_form']);
            add_action('wp_ajax_gf_ai_resolve_path_token', [$this, 'resolvePathToken']);
        }
    }
}
