<?php

declare(strict_types=1);

namespace CliqThemes\StoreLocator\I18n;

defined('ABSPATH') || exit;

// These hooks are defined by WPML and therefore intentionally use WPML's prefix.
// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound

/**
 * Registers and translates free-text UI strings that live in the database
 * (builder design labels, settings text) through whichever multilingual plugin
 * is active — WPML String Translation or Polylang's string registry.
 *
 * These strings are NOT in .pot files (they're user-authored at runtime), so
 * they can't go through __(). Instead we register each one by a stable name so
 * the site owner can translate it in WPML/Polylang's String Translation UI, and
 * resolve it for the active language on output.
 *
 * No-ops gracefully when neither plugin is active (returns the original value),
 * so single-language installs are unaffected.
 */
final class StringTranslator
{
    public const CONTEXT = 'Cliq Store Locator';

    /** Register a string so it appears in the WPML/Polylang translation UI. */
    public static function register(string $name, string $value, bool $multiline = false): void
    {
        if ($value === '') {
            return;
        }

        if (function_exists('pll_register_string')) {
            // Polylang: (name, string, group, multiline).
            pll_register_string($name, $value, self::CONTEXT, $multiline);
            return;
        }

        if (self::wpmlActive()) {
            // WPML: register under (context, name, value).
            do_action('wpml_register_single_string', self::CONTEXT, $name, $value);
        }
    }

    /** Resolve a string for the active language (registering it on the fly). */
    public static function translate(string $value, string $name): string
    {
        if ($value === '') {
            return $value;
        }

        if (function_exists('pll__') && function_exists('pll_register_string')) {
            pll_register_string($name, $value, self::CONTEXT);
            return (string) pll__($value);
        }

        if (self::wpmlActive()) {
            do_action('wpml_register_single_string', self::CONTEXT, $name, $value);
            return (string) apply_filters('wpml_translate_single_string', $value, self::CONTEXT, $name);
        }

        return $value;
    }

    private static function wpmlActive(): bool
    {
        return defined('ICL_SITEPRESS_VERSION') || has_filter('wpml_translate_single_string');
    }

    /**
     * Walk a builder design model tree, translating every user-facing text node
     * (field labels, placeholders, help, button text, headings, empty states).
     * The string name is derived from a stable prefix so translations persist
     * across reads. Returns the model with text resolved for the active language.
     *
     * @param array<string, mixed> $model
     * @param string               $prefix Stable id, e.g. "design_42".
     * @return array<string, mixed>
     */
    public static function translateModel(array $model, string $prefix): array
    {
        if (! self::anyActive()) {
            return $model;
        }

        $rows = $model['rows'] ?? null;
        if (! is_array($rows)) {
            return $model;
        }

        foreach ($rows as $ri => $row) {
            foreach (($row['columns'] ?? []) as $ci => $col) {
                foreach (($col['items'] ?? []) as $ii => $item) {
                    $base = "{$prefix}_r{$ri}_c{$ci}_i{$ii}";
                    foreach (['label', 'placeholder', 'help', 'text', 'emptyText', 'allLabel'] as $key) {
                        if (! empty($item[$key]) && is_string($item[$key])) {
                            $model['rows'][$ri]['columns'][$ci]['items'][$ii][$key]
                                = self::translate($item[$key], "{$base}_{$key}");
                        }
                    }
                    // Choice option labels.
                    if (! empty($item['options']) && is_array($item['options'])) {
                        foreach ($item['options'] as $oi => $opt) {
                            if (! empty($opt['label']) && is_string($opt['label'])) {
                                $model['rows'][$ri]['columns'][$ci]['items'][$ii]['options'][$oi]['label']
                                    = self::translate($opt['label'], "{$base}_opt{$oi}");
                            }
                        }
                    }
                }
            }
        }

        return $model;
    }

    private static function anyActive(): bool
    {
        return function_exists('pll__') || self::wpmlActive();
    }
}
