<?php
/**
 * Translation hook handlers for runtime integration.
 *
 * @package WPR_Translate
 */

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

/**
 * Override the file path returned by WordPress before a MO file is loaded.
 *
 * This handler runs on the {@see 'load_textdomain_mofile'} filter. It inspects
 * the resolved path, determines the locale, and swaps in a plugin-generated
 * file when available so that WPResidence Translate overrides ship first.
 *
 * @param string $mofile Path resolved by WordPress.
 * @param string $domain Text domain being loaded.
 *
 * @return string Potentially replaced MO file path.
 */
function wpr_translate_override_mofile( $mofile, $domain ) {
    // Log the custom directory once to avoid noisy output.
    static $logged_dir = false;
    if (!$logged_dir) {
        $dir = wpr_translate_get_custom_translations_directory();
        $logged_dir = true;
    }

    
    // Normalize input values.
    $domain = (string) $domain;
    $locale = wpr_translate_extract_locale_from_mofile( $mofile, $domain );
    
    if ( '' === $locale ) {
        // Fall back to the active locale when it cannot be parsed from the file.
        $locale = wpr_translate_get_active_locale();
    }
    
    if ( '' === $locale || '' === $domain ) {
        // Record that WordPress handled the file.
        wpr_translate_record_loaded_mofile( $domain, '', $mofile, 'wordpress' );
        return $mofile;
    }
    
    // Resolve the plugin-generated file matching the domain/locale pair.
    $custom = wpr_translate_locate_custom_mofile( $domain, $locale );
    
    
    if ( '' === $custom ) {
        // Record the default file when no custom translation exists.
        wpr_translate_record_loaded_mofile( $domain, $locale, $mofile, 'wordpress' );
        return $mofile;
    }
    
    // Record and return the custom file so WordPress loads our compiled strings.
    wpr_translate_record_loaded_mofile( $domain, $locale, $custom, 'custom' );
    
    
    // Return the custom file so WordPress loads the plugin version.
    return $custom;
}
/**
 * Override text domain loading to inject plugin-generated MO files.
 *
 * This callback executes on {@see 'override_load_textdomain'} and can stop the
 * default loader entirely. It attempts to load the plugin-generated file into
 * the `$l10n` global whenever a compiled archive exists for the domain/locale
 * combination.
 *
 * @param bool   $override Whether another handler has short-circuited loading.
 * @param string $domain   Text domain being loaded.
 * @param string $mofile   File path passed to load_textdomain().
 *
 * @return bool True when the plugin handled the loading, original override otherwise.
 */
function wpr_translate_override_load_textdomain( $override, $domain, $mofile ) {
    if ( true === $override ) {
        // Honor a previous override.
        return $override;
    }

    $domain = (string) $domain;

    if ( '' === $domain ) {
        // No domain means no custom file can be resolved.
        return $override;
    }

    $locale = wpr_translate_extract_locale_from_mofile( $mofile, $domain );

    // WordPress may not always pass a locale through the MO filename, so we
    // reuse the active language when the path is ambiguous.
    if ( '' === $locale ) {
        $locale = wpr_translate_get_active_locale();
    }

    if ( '' === $locale ) {
        // Without a locale we cannot choose the custom file.
        return $override;
    }

    // Prevent duplicate loads if a custom file has already been registered for
    // this domain/locale pair during the current request.
    if ( function_exists( 'wpr_translate_has_custom_mofile_loaded' ) && wpr_translate_has_custom_mofile_loaded( $domain, $locale ) ) {
        // Avoid loading the same custom file twice.
        return true;
    }

    // Attempt to locate the plugin-generated file for the requested locale.
    $custom = wpr_translate_locate_custom_mofile( $domain, $locale );

    if ( '' === $custom ) {
        // No custom file exists for this domain/locale.
        return $override;
    }

    if ( ! class_exists( 'MO' ) ) {
        // Load the MO parser class when needed.
        require_once ABSPATH . WPINC . '/pomo/mo.php';
    }

    // Import the custom translation file into a MO object.
    $mo = new MO();

    if ( ! $mo->import_from_file( $custom ) ) {
        // Abort if the custom file cannot be parsed.
        return $override;
    }

    global $l10n, $l10n_unloaded;

    // Ensure the storage structures exist before injecting the MO instance.
    if ( ! is_array( $l10n ) ) {
        // Ensure the global storage exists for injected domains.
        $l10n = array();
    }

    $l10n[ $domain ] = $mo;

    if ( isset( $l10n_unloaded[ $domain ] ) ) {
        // Clear the unloaded cache for this domain.
        unset( $l10n_unloaded[ $domain ] );
    }

    // Track that the custom file was used so other checks can inspect it later.
    wpr_translate_record_loaded_mofile( $domain, $locale, $custom, 'custom' );

    return true;
}

/**
 * Provide runtime translations for text domains via gettext.
 *
 * @param string $translation Translated text.
 * @param string $text        Original text.
 * @param string $domain      Text domain.
 *
 * @return string
 */
function wpr_translate_filter_gettext( $translation, $text, $domain ) {
    if ( function_exists( 'wpr_translate_maybe_provide_translation' ) ) {
        // Allow the runtime translation provider to inject overrides when
        // database-backed strings exist for this domain.
        return wpr_translate_maybe_provide_translation( $translation, $text, $domain );
    }

    return $translation;
}

/**
 * Provide runtime translations for text domains when context is supplied.
 *
 * @param string $translation Translated text.
 * @param string $text        Original text.
 * @param string $context     Context information (unused).
 * @param string $domain      Text domain.
 *
 * @return string
 */
function wpr_translate_filter_gettext_with_context( $translation, $text, $context, $domain ) {
    if ( function_exists( 'wpr_translate_maybe_provide_translation' ) ) {
        // Allow context-aware lookups to reuse the same runtime override logic.
        return wpr_translate_maybe_provide_translation( $translation, $text, $domain );
    }

    return $translation;
}

/**
 * Ensure custom theme translation files load even when the theme text domain
 * was initialised before the plugin registered its filters.
 */
function wpr_translate_maybe_reload_theme_text_domains() {
    if ( ! function_exists( 'load_textdomain' ) ) {
        // Do nothing when gettext is unavailable.
        return;
    }

    $domains = wpr_translate_collect_theme_text_domains();
    $locale  = wpr_translate_get_active_locale();

    if ( '' === $locale ) {
        // Determine the WordPress locale when none is resolved.
        if ( function_exists( 'determine_locale' ) ) {
            $locale = determine_locale();
        } else {
            $locale = get_locale();
        }
    }

    wpr_translate_reload_theme_text_domains_for_locale( $locale, $domains );
}

/**
 * Reload theme text domains for a specific locale.
 *
 * @param string     $locale  Locale identifier.
 * @param array|null $domains Optional. Pre-collected domains to reuse.
 */
function wpr_translate_reload_theme_text_domains_for_locale( $locale, $domains = null ) {
    if ( ! function_exists( 'load_textdomain' ) ) {
        // Bail out when gettext is unavailable.
        return;
    }

    $locale = (string) $locale;

    if ( '' === $locale ) {
        // Locale is required to load domain files.
        return;
    }

    if ( null === $domains ) {
        // Collect domains when none were supplied.
        $domains = wpr_translate_collect_theme_text_domains();
    }

    if ( empty( $domains ) ) {
        // Nothing to load.
        return;
    }

    static $logged_locales = array();

    $log_key = strtolower( $locale ) . '|' . implode( '|', array_map( 'strtolower', $domains ) );

    if ( ! isset( $logged_locales[ $log_key ] ) ) {
        $logged_locales[ $log_key ] = true;

        $log_payload = array(
            'locale'     => $locale,
            'domains'    => array(),
            'candidates' => array(),
        );

        if ( function_exists( 'wp_get_theme' ) ) {
            $theme = wp_get_theme();

            if ( $theme instanceof WP_Theme ) {
                $log_payload['candidates'] = array(
                    trim( (string) $theme->get( 'TextDomain' ) ),
                    trim( (string) $theme->get_template() ),
                    trim( (string) $theme->get_stylesheet() ),
                );

                if ( method_exists( $theme, 'parent' ) ) {
                    $parent = $theme->parent();

                    if ( $parent instanceof WP_Theme ) {
                        $log_payload['candidates'][] = trim( (string) $parent->get( 'TextDomain' ) );
                        $log_payload['candidates'][] = trim( (string) $parent->get_template() );
                        $log_payload['candidates'][] = trim( (string) $parent->get_stylesheet() );
                    }
                }
            }
        }

        if ( ! empty( $log_payload['candidates'] ) ) {
            $log_payload['candidates'] = array_values(
                array_unique(
                    array_filter(
                        $log_payload['candidates'],
                        'strlen'
                    )
                )
            );
        }

        foreach ( $domains as $domain ) {
            $domain = trim( (string) $domain );

            if ( '' === $domain ) {
                continue;
            }

            $log_payload['domains'][] = $domain;
        }

        if ( ! empty( $log_payload['domains'] ) ) {
            $log_payload['domains'] = array_values( array_unique( $log_payload['domains'] ) );
        }

        $encoded = function_exists( 'wp_json_encode' ) ? wp_json_encode( $log_payload ) : json_encode( $log_payload );

        if ( false === $encoded ) {
            $encoded = 'locale=' . $locale . '; domains=' . implode( ',', $log_payload['domains'] );
        }

    }

    foreach ( $domains as $domain ) {
        $domain = (string) $domain;

        if ( '' === $domain ) {
            // Skip empty entries.
            continue;
        }

        if ( function_exists( 'wpr_translate_has_custom_mofile_loaded' ) && wpr_translate_has_custom_mofile_loaded( $domain, $locale ) ) {
            // Skip domains already loaded via custom MO files.
            continue;
        }

        $custom = wpr_translate_locate_custom_mofile( $domain, $locale );

        if ( '' === $custom ) {
            // No custom translation available for this domain.
            continue;
        }

        // Load the custom MO file for this domain and locale.
        load_textdomain( $domain, $custom );
    }
}

/**
 * Collect text domains associated with the active theme and its parent.
 *
 * @return array
 */
function wpr_translate_collect_theme_text_domains() {
    if ( ! function_exists( 'wp_get_theme' ) ) {
        // Cannot inspect theme data without wp_get_theme.
        return array();
    }

    $theme = wp_get_theme();

    if ( ! $theme instanceof WP_Theme ) {
        // Abort when theme data is unavailable.
        return array();
    }

    $domains    = array();
    $candidates = array(
        $theme->get( 'TextDomain' ),
        $theme->get_template(),
        $theme->get_stylesheet(),
    );

    if ( method_exists( $theme, 'parent' ) ) {
        $parent = $theme->parent();

        if ( $parent instanceof WP_Theme ) {
            $candidates[] = $parent->get( 'TextDomain' );
            $candidates[] = $parent->get_template();
            $candidates[] = $parent->get_stylesheet();
        }
    }

    foreach ( $candidates as $candidate ) {
        $candidate = trim( (string) $candidate );

        if ( '' === $candidate ) {
            // Skip empty candidate values.
            continue;
        }

        $key = strtolower( $candidate );

        if ( 'default' === $key ) {
            // Ignore the placeholder default domain.
            continue;
        }

        if ( ! isset( $domains[ $key ] ) ) {
            // Store unique domain values.
            $domains[ $key ] = $candidate;
        }
    }

    return array_values( $domains );
}
