<?php
/*Overall Flow

WordPress calls get_terms() or get_the_terms()

These trigger the filters in this order:

get_terms_args

terms_clauses

SQL query runs and returns raw terms

get_terms or get_the_terms filters modify the final term list

🔗 Filter Connections and Roles
1. get_terms_args

Runs first, before the SQL query is built.

You can use this to add or adjust arguments like orderby, meta_query, include, etc.

Useful to inject high-level constraints into the term query (e.g., restrict by IDs of known language terms).

2. terms_clauses

Modifies the actual SQL query.

Injects JOINs and WHERE clauses, e.g., to join your custom translation table and restrict results to the current language.

Ensures only translated terms for the current language are fetched from the database.

📌 This filter ensures performance and accuracy at the DB level.

3. get_terms

Runs after the SQL executes and the raw term list is returned.

You can further filter out or manipulate the terms—e.g., remove untranslated ones, normalize formats, or sort differently.

4. get_the_terms

Like get_terms, but used when querying terms attached to a specific post.

Useful to adjust post-specific taxonomy term results, like when displaying them in metaboxes.

Example Use Case (Post Edit Screen)

When editing a post:

WordPress calls get_terms() to list terms for taxonomy metaboxes.

Your terms_clauses hook ensures the SQL only loads terms in the current language.

If fallback behavior or additional tweaks are needed, get_terms and get_the_terms let you post-process the results.

get_terms_args is used to shape the initial query args—e.g., limit to hierarchical terms or sort by name.

Visual Diagram
get_terms() or get_the_terms()
        │
        ├── get_terms_args          ← adjust args before SQL
        │
        ├── terms_clauses           ← inject JOIN + WHERE for language
        │
        ├── [SQL executes]          ← only returns terms for current lang
        │
        ├── get_terms / get_the_terms  ← final post-query filtering
        │
        └── Result: filtered terms by language


*/
/**
 * Register empty taxonomy metabox filters for post editor screens.
 *
 * These hooks will let us customize taxonomy term listings on post edit screens.
 *
 * @package WPR_Translate
 */

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

/**
 * Initialize taxonomy metabox filters for the admin post editor.
 */
function wpr_translate_bootstrap_taxonomy_metabox_filters() {
    // Delay registration until WordPress knows which admin screen is being rendered.
    add_action( 'current_screen', 'wpr_translate_register_taxonomy_metabox_filters' );
}

/**
 * Register filters for taxonomy queries when editing a post.
 *
 * @param WP_Screen $screen Current admin screen.
 */
function wpr_translate_register_taxonomy_metabox_filters( $screen ) {
    // Only apply filters on post edit screens.
    // Bail out when not editing a post in either the classic or block editor.
    if ( empty( $screen ) || ! in_array( $screen->base, array( 'post', 'post-new' ), true ) ) {
        return;
    }

    // Register argument and result filters for language-aware taxonomy term mapping.
    add_filter( 'get_terms_args', 'wpr_translate_filter_taxonomy_metabox_get_terms_args', 10, 2 );
    add_filter( 'get_terms', 'wpr_translate_filter_all_taxonomy_terms_by_language', 10, 3 );
    add_filter( 'get_the_terms', 'wpr_translate_filter_assigned_taxonomy_terms_by_language', 10, 3 );

}
/**
 * Determine the language context for admin screens.
 *
 * Prefers the language tied to the currently edited post, then falls back to
 * the user-selected admin choice, and finally the default language.
 *
 * @return string|null Language code or null when unavailable.
 */
function wpr_translate_return_current_language_admin() {
    global $pagenow;

    $post_id = null;

    // Resolve the current post ID when editing an existing post.

    if ( is_admin() && 'post.php' === $pagenow && isset( $_GET['post'] ) ) {
        $post_id = intval( $_GET['post'] );
    } elseif ( is_admin() && 'post-new.php' === $pagenow ) {
        // No post yet — fall back to default language.
        return wpr_translation_get_default_language_code( wpr_translation_get_active_languages() );
    }

    // Prefer the language assigned to the post when available.
    if ( $post_id ) {
        $post = get_post( $post_id );
        if ( $post ) {
            return wpr_translation_resolve_post_language_code( $post_id, $post->post_type );
        }
    }

    $selected_language = '';

    // Fall back to the admin-selected language if configured.
    if ( function_exists( 'wpr_translate_get_admin_selected_language_code' ) ) {
        $selected_language = wpr_translate_get_admin_selected_language_code();
    }

    if ( '' !== $selected_language ) {
        return $selected_language;
    }

    // Fall back to the default language.
    return wpr_translation_get_default_language_code( wpr_translation_get_active_languages() );
}

/**
 * Keep taxonomy term SQL clauses unchanged for metabox queries.
 *
 * Language mapping is handled after query results are loaded.
 *
 * @param array $clauses SQL clauses.
 *
 * @return array
 */
function wpr_translate_filter_taxonomy_metabox_terms_clauses( $clauses, $taxonomies, $args ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
    // Keep SQL clauses unchanged. Language mapping is now handled in term-result filters.
    return $clauses;
}



/**
 * Intercepts the arguments sent to get_terms() before the SQL query is built.
 * Injects a custom flag (wpr_language_filter) into the $args array to indicate that language filtering should be applied.

 * Stores the current language (wpestate_get_current_language()) for use later in get_terms.
 *Since get_terms does not natively know about languages, this filter is used to pass custom context forward into later filters.
 * @param array  $args       Arguments passed to get_terms.
 * @param array  $taxonomies List of taxonomy names.
 *
 * @return array Original arguments.
 */

function wpr_translate_filter_taxonomy_metabox_get_terms_args( $args, $taxonomies ) {

    // Capture the current admin language to pass forward.
    $current_language = wpr_translate_return_current_language_admin(); // e.g., 'en'

    if ( empty( $current_language ) ) {
        return $args;
    }

    // Flag to mark that we want to filter by language later.
    $args['wpr_language_filter'] = $current_language;

    return $args;
}




/**
 * Map taxonomy terms to the selected admin language using shared meta-first helpers.
 *
 * @param array        $terms            Term objects or IDs.
 * @param array|string $taxonomies       Taxonomy list.
 * @param string       $current_language Selected admin language code.
 *
 * @return array
 */
function wpr_translate_map_taxonomy_terms_for_admin_language( $terms, $taxonomies, $current_language ) {
    if ( is_wp_error( $terms ) ) {
        return $terms;
    }

    $terms            = is_array( $terms ) ? $terms : array();
    $taxonomies       = (array) $taxonomies;
    $current_language = sanitize_key( (string) $current_language );

    if ( empty( $terms ) || '' === $current_language ) {
        return $terms;
    }

    $languages        = wpr_translation_get_active_languages();
    $default_language = sanitize_key( wpr_translation_get_default_language_code( $languages ) );
    $mapped_terms     = array();
    $seen_ids         = array();
    $taxonomy_hint    = '';

    if ( ! empty( $taxonomies ) ) {
        $taxonomy_hint = sanitize_key( $taxonomies[0] );
    }

    foreach ( $terms as $term ) {
        $term_id  = 0;
        $taxonomy = '';

        if ( $term instanceof WP_Term ) {
            $term_id  = absint( $term->term_id );
            $taxonomy = sanitize_key( $term->taxonomy );
        } else {
            $term_id = absint( $term );
            $taxonomy = $taxonomy_hint;
        }

        if ( $term_id <= 0 || '' === $taxonomy ) {
            $mapped_terms[] = $term;
            continue;
        }

        if ( ! function_exists( 'wpr_translation_is_taxonomy_translatable' ) || ! wpr_translation_is_taxonomy_translatable( $taxonomy ) ) {
            $mapped_terms[] = $term;
            continue;
        }

        $canonical_term_id = $term_id;

        if ( function_exists( 'wpr_translate_resolve_original_term_id' ) ) {
            $resolved_canonical = absint( wpr_translate_resolve_original_term_id( $term_id, $taxonomy ) );

            if ( $resolved_canonical > 0 ) {
                $canonical_term_id = $resolved_canonical;
            }
        }

        $target_id = 0;

        if ( '' !== $default_language && $current_language === $default_language ) {
            $target_id = $canonical_term_id;
        } elseif ( function_exists( 'wpr_translate_lookup_translated_term_id_strict' ) ) {
            $strict_target = wpr_translate_lookup_translated_term_id_strict( $canonical_term_id, $taxonomy, $current_language );

            if ( is_numeric( $strict_target ) ) {
                $target_id = absint( $strict_target );
            }
        }

        if ( $target_id <= 0 ) {
            continue;
        }

        $seen_key = $taxonomy . '|' . $target_id;

        if ( isset( $seen_ids[ $seen_key ] ) ) {
            continue;
        }

        $seen_ids[ $seen_key ] = true;

        if ( $term instanceof WP_Term ) {
            $mapped_term = get_term( $target_id, $taxonomy );

            if ( $mapped_term instanceof WP_Term && ! is_wp_error( $mapped_term ) ) {
                $mapped_terms[] = $mapped_term;
            }
        } else {
            $mapped_terms[] = $target_id;
        }
    }

    return $mapped_terms;
}

/**
 * Filter `get_terms()` output for the selected admin language.
 *
 * @param array $terms      List of term objects or IDs.
 * @param array $taxonomies Taxonomy names.
 * @param array $args       Query arguments.
 *
 * @return array
 */
function wpr_translate_filter_all_taxonomy_terms_by_language( $terms, $taxonomies, $args ) {
    if ( is_wp_error( $terms ) ) {
        return $terms;
    }

    // Bail when no terms are present.
    if ( empty( $terms ) ) {
        return $terms;
    }

    // Read the language filter flag set earlier.
    $current_language = $args['wpr_language_filter'] ?? null;

    if ( empty( $current_language ) ) {
        return $terms;
    }

    return wpr_translate_map_taxonomy_terms_for_admin_language( $terms, $taxonomies, $current_language );
}


/**
 * Filter `get_the_terms()` output for the selected admin language.
 *
 * @param array|WP_Error $terms    Assigned terms.
 * @param int            $post_id  Post ID.
 * @param string         $taxonomy Taxonomy name.
 *
 * @return array|WP_Error
 */


function wpr_translate_filter_assigned_taxonomy_terms_by_language( $terms, $post_id, $taxonomy ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found

    if ( is_wp_error( $terms ) ) {
        return $terms;
    }

    // Resolve the current admin language for filtering.
    $current_language = wpr_translate_return_current_language_admin(); // e.g., 'en'

    if ( empty( $current_language ) || empty( $terms ) ) {
        return $terms;
    }

    return wpr_translate_map_taxonomy_terms_for_admin_language( $terms, array( $taxonomy ), $current_language );
}
