<?php
/**
 * ZERTI plugin internationalization (textdomain, admin locale, shared JS strings).
 */

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

require_once __DIR__ . '/locale-config.php';

/**
 * Relative path to the plugin languages directory (from WP plugin root).
 */
function zerti_languages_rel_path(): string
{
    return dirname(plugin_basename(ZERTI_PLUGIN_FILE)) . '/languages';
}

/**
 * Load the zerti text domain.
 *
 * WordPress 6.7+ registers plugin text domains for JIT loading via
 * load_plugin_textdomain(), but that path does not reliably apply translations
 * for custom plugin MO files. Load the locale-specific MO explicitly instead.
 */
function zerti_load_plugin_textdomain(): void
{
    $locale = function_exists('zerti_get_effective_locale')
        ? zerti_get_effective_locale()
        : determine_locale();
    $locale = apply_filters('plugin_locale', $locale, 'zerti');
    $mofile = WP_PLUGIN_DIR . '/' . zerti_languages_rel_path() . '/zerti-' . $locale . '.mo';

    unload_textdomain('zerti');

    if (is_readable($mofile)) {
        load_textdomain('zerti', $mofile);
    }
}

/**
 * Whether the current request is the ZERTI admin screen or a ZERTI AJAX handler.
 */
function zerti_is_zerti_context(): bool
{
    if (function_exists('zerti_is_zerti_admin_screen') && zerti_is_zerti_admin_screen()) {
        return true;
    }

    if (function_exists('zerti_is_zerti_ajax_request') && zerti_is_zerti_ajax_request()) {
        return true;
    }

    if (function_exists('zerti_is_zerti_admin_post_request') && zerti_is_zerti_admin_post_request()) {
        return true;
    }

    return false;
}

/**
 * admin-post.php handlers registered by ZERTI (e.g. PDF download).
 */
function zerti_is_zerti_admin_post_request(): bool
{
    if (!is_admin()) {
        return false;
    }

    $action = isset($_REQUEST['action']) ? sanitize_key(wp_unslash((string) $_REQUEST['action'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- admin-post action routing only.

    return $action !== '' && zerti_str_starts_with($action, 'zerti_');
}

/**
 * ZERTI top-level admin page (not generic wp-admin).
 */
function zerti_is_zerti_admin_screen(): bool
{
    if (!is_admin()) {
        return false;
    }

    $page = isset($_GET['page']) ? sanitize_key(wp_unslash((string) $_GET['page'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- admin screen detection only.

    return $page === ZERTI_ADMIN_PAGE_SLUG;
}

/**
 * AJAX actions registered by ZERTI (action prefix zerti_).
 */
function zerti_is_zerti_ajax_request(): bool
{
    if (!wp_doing_ajax()) {
        return false;
    }

    $action = isset($_REQUEST['action']) ? sanitize_key(wp_unslash((string) $_REQUEST['action'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- admin-post action routing only.

    return zerti_str_starts_with($action, 'zerti_');
}

/**
 * Sanitize admin locale setting (empty string = follow WordPress site language).
 */
function zerti_sanitize_admin_locale(string $value): string
{
    $value = sanitize_text_field($value);
    if ($value === '') {
        return '';
    }

    if (isset(zerti_selectable_admin_locales()[$value])) {
        return $value;
    }

    if (in_array($value, get_available_languages(), true)) {
        return $value;
    }

    return '';
}

/**
 * Stored ZERTI admin UI locale, or empty to use the WordPress site locale.
 */
function zerti_get_admin_locale(): string
{
    if (!function_exists('zerti_get_plugin_settings')) {
        return '';
    }

    $settings = zerti_get_plugin_settings();
    $raw = isset($settings['general']['admin_locale']) ? (string) $settings['general']['admin_locale'] : '';

    return zerti_sanitize_admin_locale($raw);
}

/**
 * Effective locale for ZERTI strings on this request.
 */
function zerti_get_effective_locale(): string
{
    $admin = zerti_get_admin_locale();

    return $admin !== '' ? $admin : determine_locale();
}

/**
 * Load WooCommerce translations for a specific locale (when available).
 */
function zerti_load_woocommerce_textdomain_for_locale(string $locale): void
{
    if ($locale === '' || !function_exists('load_textdomain')) {
        return;
    }

    $candidates = [
        WP_LANG_DIR . '/plugins/woocommerce-' . $locale . '.mo',
    ];

    if (function_exists('WC') && WC()) {
        $candidates[] = WC()->plugin_path() . '/i18n/languages/woocommerce-' . $locale . '.mo';
    }

    foreach ($candidates as $mofile) {
        if (!is_readable($mofile)) {
            continue;
        }
        unload_textdomain('woocommerce');
        load_textdomain('woocommerce', $mofile);

        return;
    }
}

/**
 * English msgid => translation map from locale override JSON (cached per request).
 *
 * @return array<string, string>
 */
function zerti_get_locale_override_map(): array
{
    static $cache = [];

    $locale = zerti_get_effective_locale();
    if (isset($cache[$locale])) {
        return $cache[$locale];
    }

    $map = [];
    $root = WP_PLUGIN_DIR . '/' . zerti_languages_rel_path();

    if ($locale === 'fa_IR') {
        $path = $root . '/msgid-overrides.json';
        if (is_readable($path)) {
            $data = json_decode(zerti_read_plugin_file('languages/msgid-overrides.json'), true);
            if (is_array($data)) {
                foreach ($data as $pair) {
                    if (!is_array($pair)) {
                        continue;
                    }
                    $en = trim((string) ($pair['en'] ?? ''));
                    $translated = trim((string) ($pair['fa'] ?? ''));
                    if ($en !== '' && $translated !== '' && $translated !== $en) {
                        $map[$en] = $translated;
                    }
                }
            }
        }
    } elseif ($locale !== 'en_US') {
        $path = $root . '/' . $locale . '-overrides.json';
        if (is_readable($path)) {
            $data = json_decode(zerti_read_plugin_file('languages/' . $locale . '-overrides.json'), true);
            if (is_array($data)) {
                foreach ($data as $en => $translated) {
                    if (!is_string($en) || !is_string($translated)) {
                        continue;
                    }
                    $en = trim($en);
                    $translated = trim($translated);
                    if ($en !== '' && $translated !== '' && $translated !== $en) {
                        $map[$en] = $translated;
                    }
                }
            }
        }
    }

    $cache[$locale] = $map;

    return $map;
}

/**
 * Fallback WooCommerce translations in ZERTI admin when WC language packs are missing.
 */
function zerti_filter_gettext_woocommerce(string $translation, string $text, string $domain): string
{
    static $busy = false;

    if ($busy) {
        return $translation;
    }

    if (!zerti_is_zerti_context() || ($domain !== 'woocommerce' && $domain !== 'zerti')) {
        return $translation;
    }

    $busy = true;

    $map = function_exists('zerti_get_wc_coupon_i18n_map')
        ? zerti_get_wc_coupon_i18n_map()
        : zerti_get_locale_override_map();
    $result = isset($map[$text]) ? $map[$text] : $translation;

    $busy = false;

    return $result;
}

/**
 * @param string $translation
 * @param string $text
 * @param string $context
 * @param string $domain
 */
function zerti_filter_gettext_with_context_woocommerce($translation, $text, $context, $domain)
{
    static $busy = false;

    if ($busy) {
        return $translation;
    }

    if (!zerti_is_zerti_context() || ($domain !== 'woocommerce' && $domain !== 'zerti')) {
        return $translation;
    }

    $busy = true;

    if (function_exists('zerti_get_wc_coupon_i18n_context_translation')) {
        $mapped = zerti_get_wc_coupon_i18n_context_translation((string) $context, (string) $text);
        if ($mapped !== null) {
            $busy = false;

            return $mapped;
        }
    }

    $map = function_exists('zerti_get_wc_coupon_i18n_map')
        ? zerti_get_wc_coupon_i18n_map()
        : zerti_get_locale_override_map();
    if ($context === 'coupon expiry date placeholder' && $text === 'YYYY-MM-DD' && isset($map['YYYY-MM-DD'])) {
        $busy = false;

        return $map['YYYY-MM-DD'];
    }

    $busy = false;

    return $translation;
}

/**
 * Reload WooCommerce translations for the ZERTI admin locale.
 */
function zerti_maybe_reload_woocommerce_textdomain(): void
{
    if (!zerti_is_zerti_context() || !function_exists('WC')) {
        return;
    }

    zerti_load_woocommerce_textdomain_for_locale(zerti_get_effective_locale());
}

/**
 * Use ZERTI admin locale when WooCommerce loads translations in ZERTI context.
 *
 * @param string $locale Current locale.
 * @param string $domain Text domain.
 */
function zerti_filter_woocommerce_plugin_locale(string $locale, string $domain): string
{
    if ($domain !== 'woocommerce' || !zerti_is_zerti_context()) {
        return $locale;
    }

    $admin = zerti_get_admin_locale();

    return $admin !== '' ? $admin : $locale;
}

/**
 * BCP 47 lang for the ZERTI admin shell (HTML lang attribute).
 */
function zerti_admin_html_lang(): string
{
    return str_replace('_', '-', zerti_get_effective_locale());
}

/**
 * Sample digit string for a script (used in settings labels).
 */
function zerti_digits_format_sample(string $script): string
{
    switch ($script) {
        case 'persian':
            return zerti_to_persian_digits_latin('0123456789');
        case 'arabic':
            return zerti_to_arabic_digits('0123456789');
        case 'devanagari':
            return zerti_to_devanagari_digits('0123456789');
        case 'thai':
            return zerti_to_thai_digits('0123456789');
        default:
            return '0123456789';
    }
}

/**
 * Digit script inferred from a locale (no manual digits_format override).
 */
function zerti_digit_script_from_locale(string $locale): string
{
    $locale = strtolower(str_replace('_', '-', $locale));

    if (zerti_str_starts_with($locale, 'fa')) {
        $script = 'persian';
    } elseif (zerti_str_starts_with($locale, 'ar')) {
        $script = 'arabic';
    } elseif (zerti_str_starts_with($locale, 'hi')) {
        $script = 'devanagari';
    } elseif ($locale === 'th' || zerti_str_starts_with($locale, 'th-')) {
        $script = 'thai';
    } else {
        $script = 'western';
    }

    // LTR shell without an explicit fa/ar admin locale (e.g. English UI + «WordPress default» site locale).
    if (
        $script === 'persian'
        && function_exists('zerti_get_admin_locale')
        && zerti_get_admin_locale() === ''
        && function_exists('zerti_get_text_direction')
        && zerti_get_text_direction() === 'ltr'
    ) {
        $script = 'western';
    }

    /**
     * Filter digit script inferred from a locale (automatic digits format).
     *
     * @param string $script persian|arabic|devanagari|thai|western
     * @param string $locale BCP 47-ish locale code.
     */
    return apply_filters('zerti_digit_script', $script, $locale);
}

/**
 * Resolved digit script for ZERTI admin UI (settings override or locale).
 */
function zerti_get_digit_script(?string $locale = null): string
{
    $format = function_exists('zerti_get_digits_format') ? zerti_get_digits_format() : 'auto';
    if ($format !== 'auto') {
        return $format;
    }

    if ($locale === null || $locale === '') {
        $locale = zerti_get_effective_locale();
    }

    return zerti_digit_script_from_locale($locale);
}

/**
 * Digit script for a locale: respects Regional Settings → digits format when set.
 */
function zerti_digit_script_for_locale(?string $locale = null): string
{
    return zerti_get_digit_script($locale);
}

/**
 * Selectable digits formats for Regional Settings.
 *
 * @return array<string, string> format => label
 */
function zerti_digits_format_choices(): array
{
    $auto_script = zerti_digit_script_from_locale(zerti_get_effective_locale());
    $auto_sample = zerti_digits_format_sample($auto_script);

    return [
        'auto' => sprintf(
            /* translators: %s: sample digits for the current UI language. */
            __('Automatic — follows language (%s)', 'zerti'),
            $auto_sample
        ),
        'western' => sprintf(
            /* translators: %s: Western digit sample 0123456789. */
            __('Western — %s', 'zerti'),
            zerti_digits_format_sample('western')
        ),
        'persian' => sprintf(
            /* translators: %s: Persian digit sample. */
            __('Persian — %s', 'zerti'),
            zerti_digits_format_sample('persian')
        ),
        'arabic' => sprintf(
            /* translators: %s: Arabic-Indic digit sample. */
            __('Arabic — %s', 'zerti'),
            zerti_digits_format_sample('arabic')
        ),
    ];
}

/**
 * Format ASCII digits in a string for the active admin locale.
 */
function zerti_localize_digits(string $value, ?string $locale = null): string
{
    switch (zerti_digit_script_for_locale($locale)) {
        case 'arabic':
            return zerti_to_arabic_digits($value);
        case 'persian':
            return zerti_to_persian_digits_latin($value);
        case 'devanagari':
            return zerti_to_devanagari_digits($value);
        case 'thai':
            return zerti_to_thai_digits($value);
        default:
            return zerti_to_latin_digits($value);
    }
}

/**
 * Placeholder key for HTML digit shielding (must not contain ASCII 0-9).
 */
function zerti_html_digit_placeholder_key(int $index): string
{
    $codepoint = 0xE000 + ($index % 64000);

    if (function_exists('mb_chr')) {
        return "\x7F" . mb_chr($codepoint, 'UTF-8') . "\x7F";
    }

    return "\x7F" . str_repeat("\x00", $index + 1) . "\x7F";
}

/**
 * Localize digits in HTML without altering tags or entities (e.g. &#36; for currency).
 */
function zerti_localize_digits_in_html(string $html, ?string $locale = null): string
{
    if ($html === '') {
        return '';
    }

    $tokens = [];
    $tokenized = preg_replace_callback(
        '/&(?:#x?[0-9a-fA-F]+|[a-zA-Z][a-zA-Z0-9]+);|<[^>]+>/',
        static function (array $matches) use (&$tokens): string {
            $key = zerti_html_digit_placeholder_key(count($tokens));
            $tokens[$key] = $matches[0];

            return $key;
        },
        $html
    );

    if (!is_string($tokenized)) {
        $tokenized = $html;
    }

    $localized = zerti_localize_digits($tokenized, $locale);

    return $tokens !== [] ? strtr($localized, $tokens) : $localized;
}

/**
 * Sanitized HTML with digits localized for the active admin locale.
 */
function zerti_html_localized_digits(string $html, ?string $locale = null): string
{
    if (function_exists('zerti_decode_wc_price_currency_symbol')) {
        $html = zerti_decode_wc_price_currency_symbol($html);
    }

    return wp_kses_post(zerti_localize_digits_in_html($html, $locale));
}

/**
 * Client config for JS digit localization.
 *
 * @return array{script:string,locale:string}
 */
function zerti_digit_locale_client_config(): array
{
    $locale = zerti_get_effective_locale();

    return [
        'script' => zerti_get_digit_script($locale),
        'format' => function_exists('zerti_get_digits_format') ? zerti_get_digits_format() : 'auto',
        'locale' => $locale,
    ];
}

/**
 * Default UI text direction for a selectable ZERTI admin locale.
 */
function zerti_locale_default_direction(string $locale): ?string
{
    $config = zerti_locale_config();

    return isset($config[$locale]['direction']) ? $config[$locale]['direction'] : null;
}

/**
 * Default admin calendar for a selectable ZERTI admin locale.
 */
function zerti_locale_default_calendar(string $locale): ?string
{
    $config = zerti_locale_config();

    return isset($config[$locale]['calendar']) ? $config[$locale]['calendar'] : null;
}

/**
 * Default digits format for a selectable ZERTI admin locale.
 */
function zerti_locale_default_digits(string $locale): ?string
{
    $config = zerti_locale_config();

    return isset($config[$locale]['digits']) ? $config[$locale]['digits'] : null;
}

/**
 * Client map of locale => { direction, calendar, digits } for settings UI preview.
 *
 * @return array<string, array{direction:?string,calendar:?string,digits:?string}>
 */
function zerti_locale_regional_defaults_client_config(): array
{
    $out = [];
    foreach (array_keys(zerti_selectable_admin_locales()) as $locale) {
        if ($locale === '') {
            continue;
        }
        $out[$locale] = [
            'direction' => zerti_locale_default_direction($locale),
            'calendar' => zerti_locale_default_calendar($locale),
            'digits' => zerti_locale_default_digits($locale),
        ];
    }

    return $out;
}

/**
 * Selectable admin locales for Settings → Regional Settings.
 *
 * @return array<string, string> locale => label
 */
function zerti_admin_locale_choices(): array
{
    $site = determine_locale();
    $choices = [
        '' => sprintf(
            /* translators: %s: current WordPress site locale code. */
            __('WordPress default (%s)', 'zerti'),
            $site
        ),
    ];

    $locale_labels = [
        'fa_IR' => __('Persian', 'zerti'),
        'ar' => __('Arabic', 'zerti'),
        'en_US' => __('English', 'zerti'),
        'fr_FR' => __('French', 'zerti'),
        'es_ES' => __('Spanish', 'zerti'),
        'tr_TR' => __('Turkish', 'zerti'),
        'nl_NL' => __('Dutch', 'zerti'),
        'hi_IN' => __('Hindi', 'zerti'),
        'th' => __('Thai', 'zerti'),
        'zh_CN' => __('Chinese', 'zerti'),
    ];

    foreach (zerti_selectable_admin_locales() as $locale => $label) {
        $choices[$locale] = isset($locale_labels[$locale]) ? $locale_labels[$locale] : $label;
    }

    /**
     * Filter selectable ZERTI admin locales.
     *
     * @param array<string, string> $choices
     */
    return apply_filters('zerti_admin_locale_choices', $choices);
}

/**
 * Reload zerti translations in ZERTI admin/AJAX once context and settings are ready.
 */
function zerti_maybe_reload_admin_textdomain(): void
{
    if (!zerti_is_zerti_context()) {
        return;
    }

    zerti_load_plugin_textdomain();
    zerti_maybe_reload_woocommerce_textdomain();
}

/**
 * Use the ZERTI admin locale when loading the zerti text domain in ZERTI context.
 *
 * @param string $locale Current locale.
 * @param string $domain Text domain.
 */
function zerti_filter_plugin_locale(string $locale, string $domain): string
{
    if ($domain !== 'zerti' || !zerti_is_zerti_context()) {
        return $locale;
    }

    $admin = zerti_get_admin_locale();

    return $admin !== '' ? $admin : $locale;
}

/**
 * AG Grid pagination / overlay strings shared by data grids.
 *
 * @return array<string, string>
 */
function zerti_admin_ag_grid_locale_strings(): array
{
    return [
        'more' => __('More', 'zerti'),
        'to' => __('To', 'zerti'),
        'of' => __('From', 'zerti'),
        'next' => __('Next', 'zerti'),
        'last' => __('Last', 'zerti'),
        'first' => __('First', 'zerti'),
        'previous' => __('Previous', 'zerti'),
        'loadingOoo' => __('Loading...', 'zerti'),
    ];
}

/**
 * Shared grid UI strings (columns helpers, filters, inline edit).
 *
 * @return array<string, string>
 */
function zerti_admin_grid_shared_i18n(): array
{
    return array_merge(
        zerti_admin_ag_grid_locale_strings(),
        [
            'loadingData' => __('Loading information...', 'zerti'),
            'filterAll' => __('All', 'zerti'),
            'remove' => __('Delete', 'zerti'),
            'save' => __('Save', 'zerti'),
            'cancel' => __('Cancel', 'zerti'),
            'select' => __('Select', 'zerti'),
            'noImage' => __('No image', 'zerti'),
            /* translators: %s: order status label */
            'statusFilterOnly' => __('Only «%s» orders', 'zerti'),
        ]
    );
}

/**
 * Calendar datepicker labels for JS (month names stay locale-specific via gettext).
 *
 * @return array<string, mixed>
 */
function zerti_admin_datepicker_i18n(): array
{
    return [
        'jalaliMonths' => [
            __('Farvardin', 'zerti'),
            __('Ordibehesht', 'zerti'),
            __('Khordad', 'zerti'),
            __('Tir', 'zerti'),
            __('Mordad', 'zerti'),
            __('Shahrivar', 'zerti'),
            __('Mehr', 'zerti'),
            __('Aban', 'zerti'),
            __('Azar', 'zerti'),
            __('Dey', 'zerti'),
            __('Bahman', 'zerti'),
            __('Esfand', 'zerti'),
        ],
        'jalaliWeekdays' => ['ش', 'ی', 'د', 'س', 'چ', 'پ', 'ج'],
        'hijriMonths' => [
            __('Muharram', 'zerti'),
            __('Safar', 'zerti'),
            __('Rabi al-Awwal', 'zerti'),
            __('Rabi al-Thani', 'zerti'),
            __('Jumada al-Awwal', 'zerti'),
            __('Jumada al-Thani', 'zerti'),
            __('Rajab', 'zerti'),
            __('Shaban', 'zerti'),
            __('Ramadan', 'zerti'),
            __('Shawwal', 'zerti'),
            __('Dhu al-Qadah', 'zerti'),
            __('Dhu al-Hijjah', 'zerti'),
        ],
        'hijriWeekdays' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],
        'today' => __('Today', 'zerti'),
        'todayHijri' => __('Today', 'zerti'),
        'clear' => __('Clear', 'zerti'),
        'clearHijri' => __('Clear', 'zerti'),
        'ariaJalali' => __('Select Jalali date', 'zerti'),
        'ariaHijri' => __('Select Hijri date', 'zerti'),
        'prevMonth' => __('Previous month', 'zerti'),
        'nextMonth' => __('Next month', 'zerti'),
        'prevMonthHijri' => __('Previous month', 'zerti'),
        'nextMonthHijri' => __('Next month', 'zerti'),
        'placeholderJalali' => zerti_localize_digits('1403/01/01'),
        'placeholderHijri' => zerti_localize_digits('1445/01/01'),
        'placeholderGregorian' => zerti_localize_digits('2024/01/01'),
    ];
}

/**
 * Confirm / delete dialog strings for zerti-confirm-alert.js.
 *
 * @return array<string, string>
 */
function zerti_admin_confirm_alert_i18n(): array
{
    return [
        'cancel' => __('Cancel', 'zerti'),
        'delete' => __('Delete', 'zerti'),
    ];
}

/**
 * Generic AJAX error strings for ZERTI admin JS.
 *
 * @return array<string, string>
 */
function zerti_admin_ajax_error_i18n(): array
{
    return [
        'requestForbidden' => __('Request forbidden.', 'zerti'),
        /* translators: %s: HTTP status code */
        'requestFailedHttp' => __('Request failed (HTTP %s).', 'zerti'),
    ];
}

add_action('init', 'zerti_load_plugin_textdomain', 0);
add_filter('plugin_locale', 'zerti_filter_plugin_locale', 10, 2);
add_filter('plugin_locale', 'zerti_filter_woocommerce_plugin_locale', 10, 2);
add_filter('gettext', 'zerti_filter_gettext_woocommerce', 20, 3);
add_filter('gettext_with_context', 'zerti_filter_gettext_with_context_woocommerce', 20, 4);
add_action('init', 'zerti_maybe_reload_admin_textdomain', 1);
