<?php
/**
 * Language helper functions used across the plugin.
 *
 * @package WPR_Translate
 */

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

require_once __DIR__ . '/language-manager-helpers.php';

/**
 * Retrieve the list of registered languages normalized for consistent access.
 *
 * @return array<int, array> Normalized languages keyed numerically.
 */
function wpr_translate_get_languages() {
    // Pull the stored language list from options.
    $languages = get_option( 'wpr_translate_languages', array() );

    if ( ! is_array( $languages ) ) {
        // Return an empty list if the stored value is invalid.
        return array();
    }

    // Normalize every stored language so downstream consumers receive uniform payloads.
    return array_map( 'wpr_translate_normalize_language', $languages );
}

/**
 * Determine the default language as defined in the plugin settings.
 *
 * @return array|null Default language array when configured or null when missing.
 */
function wpr_translate_get_default_language() {
    // Load all active languages without the public-only filter.
    $languages = wpr_translate_get_active_languages( false );

    if ( empty( $languages ) ) {
        // No languages configured.
        return null;
    }

    // Prefer languages explicitly flagged as default before falling back to ordering.
    foreach ( $languages as $language ) {
        if ( ! empty( $language['is_default'] ) ) {
            return $language;
        }
    }

    // Fallback to the first stored language when no explicit default flag exists.
    return $languages[0];
}

/**
 * Resolve a language entry using a slug, code, or locale identifier.
 *
 * @param string $identifier Slug, ISO code, or locale to match.
 *
 * @return array|null Matching language payload or null when not found.
 */
function wpr_translate_get_language( $identifier ) {
    if ( '' === $identifier ) {
        // Empty identifier cannot be matched.
        return null;
    }

    // Normalize the identifier for case-insensitive matching.
    $identifier = strtolower( $identifier );

    foreach ( wpr_translate_get_languages() as $language ) {
        // Match by slug first.
        if ( strtolower( $language['slug'] ) === $identifier ) {
            return $language;
        }

        // Match by language code.
        if ( strtolower( $language['code'] ) === $identifier ) {
            return $language;
        }

        // Normalize locales by replacing underscores to allow matching WordPress and browser formats.
        if ( strtolower( str_replace( '_', '-', $language['locale'] ) ) === str_replace( '_', '-', $identifier ) ) {
            return $language;
        }
    }

    return null;
}

/**
 * Infer the preferred language for the current visitor using cookies and browser hints.
 *
 * @return array|null Preferred language payload or null when nothing matches.
 */
function wpr_translate_resolve_preferred_language() {
    // Start with the configured active languages list.
    $languages = wpr_translate_get_active_languages();

    if ( empty( $languages ) ) {
        // No active languages means nothing can be resolved.
        return null;
    }

    // Respect the explicit cookie preference set by the user via the language switcher.
    $cookie = isset( $_COOKIE['wpestate_translation_lang_pref'] ) ? sanitize_text_field( wp_unslash( $_COOKIE['wpestate_translation_lang_pref'] ) ) : '';

    if ( $cookie ) {
        // Resolve the cookie value to a configured language.
        $matched = wpr_translate_get_language( $cookie );

        if ( null !== $matched && ! empty( $matched['is_active'] ) ) {
            return $matched;
        }
    }

    // Attempt to match the visitor's Accept-Language header against the configured languages.
    $browser = wpr_translate_match_browser_language( $languages );

    if ( null !== $browser ) {
        return $browser;
    }

    // Fall back to the default language when no preference matches.
    return wpr_translate_get_default_language();
}

/**
 * Fetch the language metadata associated with a specific post.
 *
 * @param int $post_id The post identifier to inspect.
 *
 * @return array|null Language payload or null if no mapping exists.
 */
function wpr_translate_get_post_language( $post_id ) {
    // Normalize the post ID for safety.
    $post_id = absint( $post_id );

    if ( ! $post_id || ! function_exists( 'get_post' ) || ! class_exists( 'WP_Post' ) ) {
        // Bail out if the post cannot be retrieved or WordPress is unavailable.
        return null;
    }

    // Fetch the post record to confirm it exists before requesting translation metadata.
    $post = get_post( $post_id );

    if ( ! ( $post instanceof WP_Post ) || ! function_exists( 'wpr_translation_resolve_post_language_code' ) ) {
        return null;
    }

    // Translation metadata is stored separately; resolve the language code via helper.
    $language_code = wpr_translation_resolve_post_language_code( $post_id, $post->post_type );

    if ( '' === $language_code ) {
        // No language mapping exists for this post.
        return null;
    }

    // Resolve the language payload from the code.
    $language = wpr_translate_get_language( $language_code );

    if ( null !== $language ) {
        return $language;
    }

    // When the language is unknown, synthesize a minimal payload so callers can continue gracefully.
    return wpr_translate_normalize_language(
        array(
            'code' => $language_code,
            'slug' => $language_code,
        )
    );
}

/**
 * Resolve the language that should be applied to the current request context.
 *
 * @param int $post_id Optional post identifier for post-specific contexts.
 *
 * @return array|null The most relevant language payload or null when unavailable.
 */
function wpr_translate_get_context_language( $post_id = 0 ) {
    // Normalize the post ID for consistent comparisons.
    $post_id = absint( $post_id );

    if ( $post_id ) {
        // Editing and viewing post detail pages should reflect the language of that post.
        $post_language = wpr_translate_get_post_language( $post_id );

        if ( null !== $post_language ) {
            return $post_language;
        }
    }

    // When no post is targeted, fall back to the visitor's explicit preference.
    $preferred = wpr_translate_resolve_preferred_language();

    if ( null !== $preferred ) {
        return $preferred;
    }

    return wpr_translate_get_default_language();
}




/**
 * Persist the language applied to the current request and optionally reload theme translations.
 *
 * @param array|null       $language Language payload to set or null to clear.
 * @param array|bool       $options  Either a bool or array with 'reload_theme_translations'.
 *
 * @return void
 */
function wpr_translate_set_current_language( $language, $options = array() ) {
    // Track the locale already reloaded during this request.
    static $reloaded_locale = null;
    $reload_translations    = false;

    // Accept either the legacy boolean or an options array for backwards compatibility.
    if ( is_bool( $options ) ) {
        $reload_translations = $options;
    } elseif ( is_array( $options ) && ! empty( $options['reload_theme_translations'] ) ) {
        $reload_translations = true;
    }
    // Store the selected language in the global cache.
    global $wpr_translate_current_language;

    if ( empty( $language ) || ! is_array( $language ) ) {
        // Clear the current language and reset any cached slug.
        $wpr_translate_current_language = null;

        if ( class_exists( 'WP_Estate_Translation' ) ) {
            WP_Estate_Translation::$current_language = null;
        }

        // Clearing the language should also reset the reload tracker to avoid stale locales.
        $reloaded_locale = null;

        return;
    }

    $wpr_translate_current_language = wpr_translate_normalize_language( $language );

    if ( class_exists( 'WP_Estate_Translation' ) ) {
        // Sync the legacy theme helper with the current language slug.
        $slug = wpr_translate_get_language_slug( $wpr_translate_current_language );

        if ( '' === $slug && ! wpr_translate_is_default_language( $wpr_translate_current_language ) && ! empty( $wpr_translate_current_language['code'] ) ) {
            // Provide the partner integration with a deterministic slug when none is explicitly configured.
            $slug = sanitize_title( $wpr_translate_current_language['code'] );
        }

        WP_Estate_Translation::$current_language = '' !== $slug ? $slug : null;
    }

    // Locale is required before WordPress can reload translations for the language.
    $current_locale = isset( $wpr_translate_current_language['locale'] ) ? (string) $wpr_translate_current_language['locale'] : '';

    if ( '' === $current_locale ) {
        // Without a locale, translations cannot be reloaded.
        $reloaded_locale = null;

        return;
    }

    // Skip redundant reloads when switching back to a locale already processed in this request.
    if ( $reloaded_locale === $current_locale ) {
        return;
    }

    if ( $reload_translations && function_exists( 'wpr_translate_reload_theme_text_domains_for_locale' ) ) {
        // Reload WordPress text domains whenever the locale changes so gettext strings stay in sync.
        wpr_translate_reload_theme_text_domains_for_locale( $current_locale );
        $reloaded_locale = $current_locale;
    }
}

/**
 * Determine the slug for a language when building URLs.
 *
 * @param array $language Language payload.
 *
 * @return string Sanitized slug or empty string for the default language.
 */
function wpr_translate_get_language_slug( $language ) {
    if ( empty( $language ) || ! is_array( $language ) ) {
        // No language payload means no slug.
        return '';
    }

    // Normalize the language payload to consistent keys.
    $language = wpr_translate_normalize_language( $language );

    if ( wpr_translate_is_default_language( $language ) ) {
        return '';
    }

    $slug = isset( $language['slug'] ) ? sanitize_title( $language['slug'] ) : '';

    if ( '' !== $slug ) {
        // Return the explicit slug when configured.
        return $slug;
    }

    // Fall back to a sanitized code so URLs remain deterministic even without explicit slug.
    return isset( $language['code'] ) ? sanitize_title( $language['code'] ) : '';
}

/**
 * Check whether a language payload represents the configured default.
 *
 * @param array $language Language payload to compare.
 *
 * @return bool True when the payload belongs to the default language.
 */
function wpr_translate_is_default_language( $language ) {
    if ( empty( $language ) || ! is_array( $language ) ) {
        // Invalid payloads cannot be default.
        return false;
    }

    // Normalize both the candidate and default payloads.
    $language = wpr_translate_normalize_language( $language );

    if ( ! empty( $language['is_default'] ) ) {
        return true;
    }

    $default = wpr_translate_get_default_language();

    if ( null === $default ) {
        // No default configured.
        return false;
    }

    $default = wpr_translate_normalize_language( $default );

    if ( ! empty( $language['code'] ) && ! empty( $default['code'] ) && strtolower( $language['code'] ) === strtolower( $default['code'] ) ) {
        return true;
    }

    if ( ! empty( $language['locale'] ) && ! empty( $default['locale'] ) ) {
        $language_locale = strtolower( str_replace( '_', '-', $language['locale'] ) );
        $default_locale  = strtolower( str_replace( '_', '-', $default['locale'] ) );

        if ( $language_locale === $default_locale ) {
            return true;
        }
    }

    if ( ! empty( $language['slug'] ) && ! empty( $default['slug'] ) && strtolower( $language['slug'] ) === strtolower( $default['slug'] ) ) {
        // Slug equality is the final fallback because it mirrors how URLs are routed.
        return true;
    }

    return false;
}
