<?php
/**
 * Taxonomy Translation class - manages taxonomy term translations
 *
 * @package LangForge
 */

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

class LF_Taxonomy_Translation {

    private static $instance = null;

    /** @var array In-memory cache: "element_type:element_id" => language_code */
    private $lang_cache = [];

    /** @var array In-memory cache: "element_type:element_id" => [lang => term_id, ...] */
    private $translations_cache = [];

    /** @var array In-memory cache: "element_type:element_id" => translation_group */
    private $group_cache = [];

    /** @var bool Whether taxonomy translations have been preloaded */
    private $preloaded = false;

    public static function instance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {
        $this->init_hooks();
    }

    private function init_hooks() {
        // Add language fields to term edit screens
        add_action('created_term', [$this, 'save_term_language'], 10, 3);
        add_action('edited_term', [$this, 'save_term_language'], 10, 3);

        // Add language column to term list
        add_action('admin_init', [$this, 'register_taxonomy_columns']);

        // Add language fields to term forms
        add_action('admin_init', [$this, 'register_taxonomy_fields']);

        // Filter terms by language on frontend
        add_filter('get_terms_args', [$this, 'filter_terms_by_language'], 10, 2);
        add_filter('get_terms', [$this, 'filter_terms_results'], 10, 4);

        // AJAX handlers
        add_action('wp_ajax_lf_link_term_translation', [$this, 'ajax_link_term_translation']);
        add_action('wp_ajax_lf_unlink_term_translation', [$this, 'ajax_unlink_term_translation']);

        // Clean up on term deletion
        add_action('pre_delete_term', [$this, 'delete_term_translation_record'], 10, 2);
    }

    /**
 * Register language column for all public taxonomies
 */
    public function register_taxonomy_columns() {
        $taxonomies = get_taxonomies(['public' => true], 'names');
        foreach ($taxonomies as $taxonomy) {
            add_filter("manage_edit-{$taxonomy}_columns", [$this, 'add_language_column']);
            add_filter("manage_{$taxonomy}_custom_column", [$this, 'render_language_column'], 10, 3);
        }
    }

    /**
 * Register language fields for all public taxonomy forms
 */
    public function register_taxonomy_fields() {
        $taxonomies = get_taxonomies(['public' => true], 'names');
        foreach ($taxonomies as $taxonomy) {
            add_action("{$taxonomy}_add_form_fields", [$this, 'add_term_language_field']);
            add_action("{$taxonomy}_edit_form_fields", [$this, 'edit_term_language_field'], 10, 2);
        }
    }

    /**
 * Add language field to "Add New Term" form
 */
    public function add_term_language_field($taxonomy) {
        $languages = LF_Core::instance()->get_active_languages();
        $default_lang = LF_Core::instance()->get_default_language();
        ?>
        <div class="form-field">
            <label for="lf_term_language"><?php esc_html_e('Language', 'langforge'); ?></label>
            <select name="lf_term_language" id="lf_term_language">
                <?php foreach ($languages as $code => $lang): ?>
                    <option value="<?php echo esc_attr($code); ?>" <?php selected($default_lang, $code); ?>>
                        <?php echo esc_html($lang['native_name']); ?>
                    </option>
                <?php endforeach; ?>
            </select>
            <p><?php esc_html_e('Select the language for this term.', 'langforge'); ?></p>
        </div>
        <?php
    }

    /**
 * Add language field to "Edit Term" form
 */
    public function edit_term_language_field($term, $taxonomy) {
        $languages = LF_Core::instance()->get_active_languages();
        $current_lang = $this->get_term_language($term->term_id, $taxonomy);
        $translations = $this->get_term_translations($term->term_id, $taxonomy);
        ?>
        <tr class="form-field">
            <th scope="row"><label for="lf_term_language"><?php esc_html_e('Language', 'langforge'); ?></label></th>
            <td>
                <select name="lf_term_language" id="lf_term_language">
                    <?php foreach ($languages as $code => $lang): ?>
                        <option value="<?php echo esc_attr($code); ?>" <?php selected($current_lang, $code); ?>>
                            <?php echo esc_html($lang['native_name']); ?>
                        </option>
                    <?php endforeach; ?>
                </select>
            </td>
        </tr>
        <tr class="form-field">
            <th scope="row"><?php esc_html_e('Translations', 'langforge'); ?></th>
            <td>
                <div class="avl-term-translations">
                    <?php foreach ($languages as $code => $lang): ?>
                        <?php if ($code === $current_lang) continue; ?>
                        <div class="avl-term-translation-item" style="margin-bottom:8px;">
                            <strong><?php echo esc_html($lang['native_name']); ?>:</strong>
                            <?php if (isset($translations[$code])): ?>
                                <?php $trans_term = get_term($translations[$code]); ?>
                                <?php if ($trans_term && !is_wp_error($trans_term)): ?>
                                    <a href="<?php echo esc_url(get_edit_term_link($translations[$code], $taxonomy)); ?>">
                                        <?php echo esc_html($trans_term->name); ?>
                                    </a>
                                    <button type="button" class="button button-small avl-unlink-term-translation"
                                            data-term-id="<?php echo esc_attr($term->term_id); ?>"
                                            data-taxonomy="<?php echo esc_attr($taxonomy); ?>"
                                            data-lang="<?php echo esc_attr($code); ?>"
                                            style="color:#dc3232;">x</button>
                                <?php endif; ?>
                            <?php else: ?>
                                <input type="number" name="lf_term_link[<?php echo esc_attr($code); ?>]"
                                       placeholder="<?php esc_attr_e('Term ID to link', 'langforge'); ?>"
                                       style="width:120px;" min="1">
                                <span class="description"><?php esc_html_e('Enter term ID', 'langforge'); ?></span>
                            <?php endif; ?>
                        </div>
                    <?php endforeach; ?>
                </div>
            </td>
        </tr>
        <?php
    }

    /**
 * Save term language when created or edited
 */
    public function save_term_language($term_id, $tt_id, $taxonomy) {
        // Nonce verified by WP core edit-term screen (created_term/edited_term hooks).
        // phpcs:disable WordPress.Security.NonceVerification.Missing -- Nonce verified by WP core edit-term screen.
        if (!isset($_POST['lf_term_language'])) {
            return;
        }

        $language = sanitize_text_field(wp_unslash($_POST['lf_term_language']));
        $this->set_term_language($term_id, $taxonomy, $language);

        // Handle linking translations
        if (isset($_POST['lf_term_link']) && is_array($_POST['lf_term_link'])) {
            foreach (wp_unslash($_POST['lf_term_link']) as $lang => $target_term_id) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Keys/values sanitized per-item below (intval + sanitize_text_field).
                $target_term_id = intval($target_term_id);
                if ($target_term_id > 0) {
                    $lang = sanitize_text_field($lang);
                    $this->set_term_language($target_term_id, $taxonomy, $lang);
                    $this->link_term_translations($term_id, $target_term_id, $taxonomy);
                }
            }
        }
        // phpcs:enable WordPress.Security.NonceVerification.Missing
    }

    /**
 * Preload all taxonomy translations in one query to avoid N+1.
 * Called automatically on first taxonomy lookup on frontend.
 */
    public function preload_taxonomy_translations() {
        if ($this->preloaded) return;
        $this->preloaded = true;

        global $wpdb;
        $table = $wpdb->prefix . 'lf_translations';

        // Load ALL taxonomy translations (element_type starts with 'tax_') in one query
        $rows = $wpdb->get_results( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; direct query intended.
            "SELECT element_id, element_type, language_code, translation_group FROM $table WHERE element_type LIKE 'tax_%'" // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name from $wpdb->prefix; static query, no user values.
        );

        if (!$rows) return;

        // Build lang_cache and group_cache
        foreach ($rows as $r) {
            $key = $r->element_type . ':' . $r->element_id;
            $this->lang_cache[$key] = $r->language_code;
            $this->group_cache[$key] = (int) $r->translation_group;
        }

        // Build translations_cache (group all rows by translation_group)
        $groups = [];
        foreach ($rows as $r) {
            $groups[(int) $r->translation_group][] = $r;
        }
        foreach ($groups as $group_rows) {
            $translations = [];
            $element_type = $group_rows[0]->element_type;
            foreach ($group_rows as $r) {
                $translations[$r->language_code] = (int) $r->element_id;
            }
            // Cache for every member of the group
            foreach ($group_rows as $r) {
                $key = $r->element_type . ':' . $r->element_id;
                $this->translations_cache[$key] = $translations;
            }
        }
    }

    /**
 * Get the language of a term (cached)
 *
 * on the frontend we preload EVERY tax_* row in a single query,
 * then treat any term missing from the cache as "default language, no
 * translation record". Previously only the very first cache-miss ran
 * the preload path — every subsequent miss after `preloaded=true` fell
 * through to an individual SELECT. With many untranslated terms (menu
 * items, category widgets, related-posts blocks) that regressed N+1.
 *
 * Now: whenever we're on the frontend and the key is missing, we
 * guarantee preload has run once, then negatively cache misses as the
 * site's default language. Admin keeps the individual-query fallback
 * because admin screens touch a bounded set of terms.
 */
    public function get_term_language($term_id, $taxonomy = '') {
        $element_type = 'tax_' . $taxonomy;
        $key = $element_type . ':' . $term_id;

        if (isset($this->lang_cache[$key])) {
            return $this->lang_cache[$key];
        }

        if (!is_admin()) {
            if (!$this->preloaded) {
                $this->preload_taxonomy_translations();
                if (isset($this->lang_cache[$key])) {
                    return $this->lang_cache[$key];
                }
            }
            // Preload already ran (or just did) and this term has no row →
            // default language. Negative-cache so repeated lookups stay O(1).
            $default = LF_Core::instance()->get_default_language();
            $this->lang_cache[$key] = $default;
            return $default;
        }

        // Admin fallback: individual query + cache
        global $wpdb;
        $table = $wpdb->prefix . 'lf_translations';
        $lang = $wpdb->get_var($wpdb->prepare( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; direct query intended.
            "SELECT language_code FROM $table WHERE element_id = %d AND element_type = %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name from $wpdb->prefix, values are %-prepared.
            $term_id, $element_type
        ));

        $this->lang_cache[$key] = $lang ?: LF_Core::instance()->get_default_language();
        return $this->lang_cache[$key];
    }

    /**
 * Set the language of a term
 */
    public function set_term_language($term_id, $taxonomy, $language) {
        // Invalidate cache
        $key = 'tax_' . $taxonomy . ':' . $term_id;
        unset($this->lang_cache[$key], $this->translations_cache[$key], $this->group_cache[$key]);

        global $wpdb;
        $table = $wpdb->prefix . 'lf_translations';
        $element_type = 'tax_' . $taxonomy;

        $existing = $wpdb->get_row($wpdb->prepare( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; direct query intended.
            "SELECT * FROM $table WHERE element_id = %d AND element_type = %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name from $wpdb->prefix, values are %-prepared.
            $term_id, $element_type
        ));

        if ($existing) {
            $wpdb->update( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; direct query intended.
                $table,
                ['language_code' => $language],
                ['id' => $existing->id]
            );
        } else {
            $max_group = $wpdb->get_var("SELECT MAX(translation_group) FROM $table"); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; direct query intended.
            $new_group = ($max_group ?: 0) + 1;

            $wpdb->insert($table, [ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; direct query intended.
                'element_id' => $term_id,
                'element_type' => $element_type,
                'translation_group' => $new_group,
                'language_code' => $language,
            ]);
        }
    }

    /**
 * Get all translations for a term (cached)
 *
 * Same fix as get_term_language: frontend preload + negative
 * cache on miss, so post-preload lookups never run per-term SQL.
 */
    public function get_term_translations($term_id, $taxonomy) {
        $element_type = 'tax_' . $taxonomy;
        $key = $element_type . ':' . $term_id;

        if (isset($this->translations_cache[$key])) {
            return $this->translations_cache[$key];
        }

        if (!is_admin()) {
            if (!$this->preloaded) {
                $this->preload_taxonomy_translations();
                if (isset($this->translations_cache[$key])) {
                    return $this->translations_cache[$key];
                }
            }
            $this->translations_cache[$key] = [];
            return [];
        }

        // Admin fallback: individual query + cache
        global $wpdb;
        $table = $wpdb->prefix . 'lf_translations';

        $group = $wpdb->get_var($wpdb->prepare( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; direct query intended.
            "SELECT translation_group FROM $table WHERE element_id = %d AND element_type = %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name from $wpdb->prefix, values are %-prepared.
            $term_id, $element_type
        ));

        if (!$group) {
            $this->translations_cache[$key] = [];
            return [];
        }

        $results = $wpdb->get_results($wpdb->prepare( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; direct query intended.
            "SELECT element_id, language_code FROM $table WHERE translation_group = %d AND element_type = %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name from $wpdb->prefix, values are %-prepared.
            $group, $element_type
        ), ARRAY_A);

        $translations = [];
        foreach ($results as $row) {
            $translations[$row['language_code']] = (int) $row['element_id'];
        }

        // Cache for all members of this group
        foreach ($translations as $lang => $tid) {
            $this->translations_cache[$element_type . ':' . $tid] = $translations;
        }

        return $translations;
    }

    /**
 * Get a specific translation for a term
 */
    public function get_term_translation($term_id, $taxonomy, $language) {
        $translations = $this->get_term_translations($term_id, $taxonomy);
        return $translations[$language] ?? null;
    }

    /**
 * Link two terms as translations
 */
    public function link_term_translations($term_id_1, $term_id_2, $taxonomy) {
        global $wpdb;
        $table = $wpdb->prefix . 'lf_translations';
        $element_type = 'tax_' . $taxonomy;

        $group1 = $wpdb->get_var($wpdb->prepare( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; direct query intended.
            "SELECT translation_group FROM $table WHERE element_id = %d AND element_type = %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name from $wpdb->prefix, values are %-prepared.
            $term_id_1, $element_type
        ));

        $group2 = $wpdb->get_var($wpdb->prepare( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; direct query intended.
            "SELECT translation_group FROM $table WHERE element_id = %d AND element_type = %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name from $wpdb->prefix, values are %-prepared.
            $term_id_2, $element_type
        ));

        if ($group1 && $group2 && $group1 !== $group2) {
            $wpdb->update( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; direct query intended.
                $table,
                ['translation_group' => $group1],
                ['translation_group' => $group2, 'element_type' => $element_type]
            );
        } elseif ($group1 && !$group2) {
            $lang2 = $this->get_term_language($term_id_2, $taxonomy);
            $wpdb->insert($table, [ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; direct query intended.
                'element_id' => $term_id_2,
                'element_type' => $element_type,
                'translation_group' => $group1,
                'language_code' => $lang2,
            ]);
        } elseif (!$group1 && $group2) {
            $lang1 = $this->get_term_language($term_id_1, $taxonomy);
            $wpdb->insert($table, [ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; direct query intended.
                'element_id' => $term_id_1,
                'element_type' => $element_type,
                'translation_group' => $group2,
                'language_code' => $lang1,
            ]);
        }
    }

    /**
 * Add language column to term list tables
 */
    public function add_language_column($columns) {
        $columns['lf_language'] = __('Language', 'langforge');
        return $columns;
    }

    /**
 * Render language column in term list
 */
    public function render_language_column($content, $column_name, $term_id) {
        if ($column_name !== 'lf_language') {
            return $content;
        }

        $screen = get_current_screen();
        $taxonomy = $screen ? $screen->taxonomy : '';
        $lang = $this->get_term_language($term_id, $taxonomy);

        return '<span class="lf-lang-badge">' . esc_html(strtoupper($lang)) . '</span>';
    }

    /**
 * Filter terms by language on frontend queries
 */
    public function filter_terms_by_language($args, $taxonomies) {
        if (is_admin()) {
            return $args;
        }

        // Don't filter if explicitly told not to
        if (!empty($args['lf_skip_language_filter'])) {
            return $args;
        }

        return $args;
    }

    /**
 * Filter term results by current language on frontend
 */
    public function filter_terms_results($terms, $taxonomies, $args, $term_query) {
        if (is_admin() || empty($terms)) {
            return $terms;
        }

        if (!empty($args['lf_skip_language_filter'])) {
            return $terms;
        }

        $current_lang = LF_Core::instance()->get_current_language();
        $default_lang = LF_Core::instance()->get_default_language();

        // Only filter if terms are objects (not just IDs or names)
        if (!is_object(reset($terms))) {
            return $terms;
        }

        $taxonomy = is_array($taxonomies) ? reset($taxonomies) : $taxonomies;

        $filtered = [];
        foreach ($terms as $term) {
            $term_lang = $this->get_term_language($term->term_id, $taxonomy);

            // Show term if it matches current language or has no language set
            if ($term_lang === $current_lang || $term_lang === $default_lang) {
                // Prefer current language translation if available
                $translations = $this->get_term_translations($term->term_id, $taxonomy);
                if (isset($translations[$current_lang])) {
                    // If this term IS the current language version, keep it
                    if ($translations[$current_lang] == $term->term_id) {
                        $filtered[] = $term;
                    }
                    // If there's a translation, skip the default version (will be added via translation)
                } else {
                    $filtered[] = $term;
                }
            } elseif ($term_lang === $current_lang) {
                $filtered[] = $term;
            }
        }

        return $filtered;
    }

    /**
 * AJAX: Link term translation
 */
    public function ajax_link_term_translation() {
        check_ajax_referer('lf_admin_nonce', 'nonce');

        if (!current_user_can('manage_categories')) {
            wp_send_json_error(['message' => __('Permission denied', 'langforge')]);
        }

        $term_id = intval($_POST['term_id'] ?? 0);
        $target_term_id = intval($_POST['target_term_id'] ?? 0);
        $taxonomy = sanitize_text_field(wp_unslash($_POST['taxonomy'] ?? ''));
        $language = sanitize_text_field(wp_unslash($_POST['language'] ?? ''));

        $this->set_term_language($target_term_id, $taxonomy, $language);
        $this->link_term_translations($term_id, $target_term_id, $taxonomy);

        wp_send_json_success(['message' => __('Term translation linked', 'langforge')]);
    }

    /**
 * AJAX: Unlink term translation
 */
    public function ajax_unlink_term_translation() {
        check_ajax_referer('lf_admin_nonce', 'nonce');

        if (!current_user_can('manage_categories')) {
            wp_send_json_error(['message' => __('Permission denied', 'langforge')]);
        }

        $term_id = intval($_POST['term_id'] ?? 0);
        $taxonomy = sanitize_text_field(wp_unslash($_POST['taxonomy'] ?? ''));
        $language = sanitize_text_field(wp_unslash($_POST['language'] ?? ''));

        global $wpdb;
        $table = $wpdb->prefix . 'lf_translations';
        $element_type = 'tax_' . $taxonomy;

        $group = $wpdb->get_var($wpdb->prepare( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; direct query intended.
            "SELECT translation_group FROM $table WHERE element_id = %d AND element_type = %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name from $wpdb->prefix, values are %-prepared.
            $term_id, $element_type
        ));

        if ($group) {
            $wpdb->delete($table, [ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; direct query intended.
                'translation_group' => $group,
                'language_code' => $language,
                'element_type' => $element_type,
            ]);
        }

        wp_send_json_success(['message' => __('Term translation unlinked', 'langforge')]);
    }

    /**
 * Clean up translation records when a term is deleted
 */
    public function delete_term_translation_record($term_id, $taxonomy) {
        global $wpdb;
        $table = $wpdb->prefix . 'lf_translations';
        $element_type = 'tax_' . $taxonomy;

        $wpdb->delete($table, [ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; direct query intended.
            'element_id' => $term_id,
            'element_type' => $element_type,
        ]);
    }
}
