<?php
/**
 * Language Switcher class - handles frontend language switching
 * 
 * @package LangForge
 */

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

// IDE hints for autoloaded classes
if (false) {
    class LF_Core {}
}

class LF_Language_Switcher {
    
    private static $instance = null;
    
    public static function instance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    private function __construct() {
        $this->init_hooks();
    }
    
    private function init_hooks() {
        // Register widget
        add_action('widgets_init', [$this, 'register_widget']);
        
        // Add shortcode
        add_shortcode('lf_language_switcher', [$this, 'shortcode']);
        
        // Enqueue styles
        add_action('wp_enqueue_scripts', [$this, 'enqueue_styles']);
        
        // the admin-bar switcher is now owned entirely by
        // LF_Core::add_admin_bar_switcher (also hooked on admin_bar_menu
        // priority 100). Keeping this hook registered caused two
        // overlapping switchers on the same node id — a mix of emoji
        // children (from Core) and <img> children (from here) with
        // different alignment and margins. We intentionally do NOT
        // register our own admin_bar_menu hook any more; the method
        // below is preserved in case something still calls it directly.
        // add_action('admin_bar_menu', [$this, 'admin_bar_menu'], 100);
    }
    
    /**
 * Register language switcher widget
 */
    public function register_widget() {
        register_widget('LF_Language_Switcher_Widget');
    }
    
    /**
 * Shortcode for language switcher
 */
    public function shortcode($atts) {
        // fall back to the saved Switcher setting so "Style: Dropdown"
        // on the settings page actually reaches shortcode output instead of
        // being overridden by a hard-coded default.
        $atts = shortcode_atts([
            'style'        => get_option('lf_switcher_style', 'dropdown'),
            'show_flags'   => get_option('lf_switcher_show_flags', '1') ? 'yes' : 'no',
            'show_names'   => get_option('lf_switcher_show_names', '1') ? 'yes' : 'no',
            'show_current' => get_option('lf_switcher_show_current', '1') ? 'yes' : 'no',
        ], $atts);

        ob_start();
        $this->render($atts);
        return ob_get_clean();
    }

    /**
 * Render language switcher
 */
    public function render($args = []) {
        // default from saved global settings, not hard-coded values.
        $defaults = [
            'style'        => get_option('lf_switcher_style', 'dropdown'),
            'show_flags'   => (bool) get_option('lf_switcher_show_flags', '1'),
            'show_names'   => (bool) get_option('lf_switcher_show_names', '1'),
            'show_current' => (bool) get_option('lf_switcher_show_current', '1'),
        ];
        
        $args = wp_parse_args($args, $defaults);
        
        // Convert string booleans
        foreach (['show_flags', 'show_names', 'show_current'] as $key) {
            if (is_string($args[$key])) {
                $args[$key] = $args[$key] === 'yes' || $args[$key] === '1' || $args[$key] === 'true';
            }
        }
        
        $languages = LF_Core::instance()->get_languages_for_switcher();
        $current_lang = LF_Core::instance()->get_current_language();
        
        if (empty($languages)) {
            return;
        }
        
        switch ($args['style']) {
            case 'list':
                $this->render_list($languages, $current_lang, $args);
                break;
            case 'flags':
                $this->render_flags($languages, $current_lang, $args);
                break;
            case 'plain':
                $this->render_plain($languages, $current_lang, $args);
                break;
            case 'dropdown':
            default:
                $this->render_dropdown($languages, $current_lang, $args);
                break;
        }
    }
    
    /**
 * render a single flag for the frontend switcher. Uses an SVG
 * from /assets/flags/ when one exists on disk; otherwise falls back to
 * the Unicode regional-indicator emoji for the country code. Keeps the
 * `wpml-ls-flag` class so existing theme CSS (size, border, spacing)
 * continues to apply uniformly whether the result is an <img> or a
 * <span>.
 */
    private function render_flag_for_switcher($lang) {
        $flag = isset($lang['flag']) ? strtolower((string) $lang['flag']) : '';
        if ($flag === '') {
            // Legacy calls that only had the URL — pull the filename off the
            // country_flag_url (e.g. .../flags/fr.svg → 'fr').
            $url = $lang['country_flag_url'] ?? '';
            if ($url && preg_match('#/flags/([a-z]{2})\.svg$#i', $url, $m)) {
                $flag = strtolower($m[1]);
            }
        }
        $alt = $lang['native_name'] ?? '';
        $svg = $flag !== '' ? (LF_PLUGIN_DIR . 'assets/flags/' . $flag . '.svg') : '';
        if ($flag !== '' && $svg && file_exists($svg)) {
            return '<img class="wpml-ls-flag" src="'
                 . esc_url(LF_PLUGIN_URL . 'assets/flags/' . $flag . '.svg')
                 . '" alt="' . esc_attr($alt) . '">';
        }
        if (preg_match('/^[a-z]{2}$/', $flag)) {
            $ri = function ($ch) {
                $cp = 0x1F1E6 + (ord($ch) - ord('a'));
                return mb_convert_encoding('&#' . $cp . ';', 'UTF-8', 'HTML-ENTITIES');
            };
            return '<span class="wpml-ls-flag wpml-ls-flag--emoji" role="img" aria-label="'
                 . esc_attr($alt) . '">' . $ri($flag[0]) . $ri($flag[1]) . '</span>';
        }
        // Unknown code — muted badge (keeps row height stable).
        return '<span class="wpml-ls-flag wpml-ls-flag--badge" aria-hidden="true">'
             . esc_html(strtoupper($flag)) . '</span>';
    }

    /**
 * Render dropdown style
 */
    private function render_dropdown($languages, $current_lang, $args) {
        $current = $languages[$current_lang] ?? reset($languages);
        // When the admin hides both flags and names, fall back to the
        // uppercase language code so the chip / list items aren't empty
        // boxes. Without this the switcher renders as a blank rectangle
        // and users can't tell there's anything to click.
        $code_fallback = !$args['show_flags'] && !$args['show_names'];
        ?>
        <div class="lf-language-switcher lf-dropdown wpml-ls-statics-shortcode_actions wpml-ls wpml-ls-touch-device wpml-ls-legacy-dropdown js-wpml-ls-legacy-dropdown">
            <ul>
                <li class="wpml-ls-slot-shortcode_actions wpml-ls-item wpml-ls-item-<?php echo esc_attr($current_lang); ?> wpml-ls-current-language wpml-ls-first-item wpml-ls-item-legacy-dropdown">
                    <a href="#" class="lf-current-lang wpml-ls-link">
                        <?php if ($args['show_flags']): ?>
                            <?php echo $this->render_flag_for_switcher($current); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted pre-built markup (emoji fallback for codes without SVG) ?>
                        <?php endif; ?>
                        <?php if ($args['show_names']): ?>
                            <span class="wpml-ls-native"><?php echo esc_html($current['native_name']); ?></span>
                        <?php elseif ($code_fallback): ?>
                            <span class="wpml-ls-native lf-lang-code"><?php echo esc_html(strtoupper($current_lang)); ?></span>
                        <?php endif; ?>
                        <span class="lf-dropdown-caret" aria-hidden="true">&#9662;</span>
                    </a>
                    <ul class="lf-lang-dropdown wpml-ls-sub-menu">
                        <?php foreach ($languages as $code => $lang): ?>
                            <?php if (!$args['show_current'] && $code === $current_lang) continue; ?>
                            <li class="wpml-ls-slot-shortcode_actions wpml-ls-item wpml-ls-item-<?php echo esc_attr($code); ?><?php echo $code === $current_lang ? ' wpml-ls-current-language' : ''; ?>">
                                <a href="<?php echo esc_url($lang['url']); ?>" class="wpml-ls-link" data-lang="<?php echo esc_attr($code); ?>">
                                    <?php if ($args['show_flags']): ?>
                                        <?php echo $this->render_flag_for_switcher($lang); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted pre-built markup ?>
                                    <?php endif; ?>
                                    <?php if ($args['show_names']): ?>
                                        <span class="wpml-ls-native"><?php echo esc_html($lang['native_name']); ?></span>
                                    <?php elseif ($code_fallback): ?>
                                        <span class="wpml-ls-native lf-lang-code"><?php echo esc_html(strtoupper($code)); ?></span>
                                    <?php endif; ?>
                                </a>
                            </li>
                        <?php endforeach; ?>
                    </ul>
                </li>
            </ul>
        </div>
        <?php
    }
    
    /**
 * Render list style
 */
    private function render_list($languages, $current_lang, $args) {
        $code_fallback = !$args['show_flags'] && !$args['show_names'];
        ?>
        <ul class="lf-language-switcher lf-list wpml-ls-statics-shortcode_actions wpml-ls wpml-ls-legacy-list-horizontal">
            <?php foreach ($languages as $code => $lang): ?>
                <?php if (!$args['show_current'] && $code === $current_lang) continue; ?>
                <li class="wpml-ls-slot-shortcode_actions wpml-ls-item wpml-ls-item-<?php echo esc_attr($code); ?><?php echo $code === $current_lang ? ' wpml-ls-current-language' : ''; ?>">
                    <a href="<?php echo esc_url($lang['url']); ?>" class="wpml-ls-link" data-lang="<?php echo esc_attr($code); ?>">
                        <?php if ($args['show_flags']): ?>
                            <?php echo $this->render_flag_for_switcher($lang); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted pre-built markup ?>
                        <?php endif; ?>
                        <?php if ($args['show_names']): ?>
                            <span class="wpml-ls-native"><?php echo esc_html($lang['native_name']); ?></span>
                        <?php elseif ($code_fallback): ?>
                            <span class="wpml-ls-native lf-lang-code"><?php echo esc_html(strtoupper($code)); ?></span>
                        <?php endif; ?>
                    </a>
                </li>
            <?php endforeach; ?>
        </ul>
        <?php
    }
    
    /**
 * Render flags only style
 */
    private function render_flags($languages, $current_lang, $args) {
        ?>
        <div class="lf-language-switcher lf-flags wpml-ls-statics-shortcode_actions wpml-ls">
            <?php foreach ($languages as $code => $lang): ?>
                <?php if (!$args['show_current'] && $code === $current_lang) continue; ?>
                <a href="<?php echo esc_url($lang['url']); ?>"
                   class="lf-flag-link wpml-ls-link<?php echo $code === $current_lang ? ' wpml-ls-current-language' : ''; ?>"
                   title="<?php echo esc_attr($lang['native_name']); ?>"
                   data-lang="<?php echo esc_attr($code); ?>">
                    <?php echo $this->render_flag_for_switcher($lang); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted pre-built markup ?>
                </a>
            <?php endforeach; ?>
        </div>
        <?php
    }

    /**
 * Render plain style — unstyled inline links, no dropdown, no wrapper classes.
 * Useful for themes that want full control over switcher appearance.
 */
    private function render_plain($languages, $current_lang, $args) {
        ?>
        <span class="lf-language-switcher lf-plain">
            <?php $i = 0; foreach ($languages as $code => $lang): ?>
                <?php if (!$args['show_current'] && $code === $current_lang) continue; ?>
                <?php if ($i > 0) echo ' '; $i++; ?>
                <a href="<?php echo esc_url($lang['url']); ?>"
                   data-lang="<?php echo esc_attr($code); ?>"
                   <?php if ($code === $current_lang): ?>class="is-active" aria-current="true"<?php endif; ?>><?php
                    if ($args['show_flags']):
                        // same SVG-else-emoji fallback as the other
                        // render paths; inline sizing preserved for the plain
                        // layout which doesn't pull in switcher.css.
                        echo '<span style="display:inline-block;width:16px;height:12px;vertical-align:middle;margin-right:3px;line-height:12px;font-size:13px;text-align:center;overflow:hidden;">'
                           . $this->render_flag_for_switcher($lang) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Pre-escaped trusted markup (esc_url/esc_attr/esc_html applied inside render_flag_for_switcher).
                           . '</span>';
                    endif;
                    if ($args['show_names']):
                        $label = !empty($lang['display_name']) ? $lang['display_name'] : ($lang['native_name'] ?? $code);
                        echo esc_html($label);
                    else:
                        echo esc_html(strtoupper($code));
                    endif;
                ?></a>
            <?php endforeach; ?>
        </span>
        <?php
    }
    
    /**
 * Enqueue frontend styles
 */
    public function enqueue_styles() {
        // LF_VERSION is a frozen string '1.0.0' so bumping the CSS didn't
        // invalidate long-lived browser caches on Hostinger (max-age=7d).
        // File mtime varies with every edit — use it as the version param
        // so edited CSS lands on the user's browser without a manual
        // Cmd+Shift+R.
        $css_path = LF_PLUGIN_DIR . 'assets/css/language-switcher.css';
        $ver = file_exists($css_path) ? filemtime($css_path) : LF_VERSION;
        wp_enqueue_style(
            'lf-language-switcher',
            LF_PLUGIN_URL . 'assets/css/language-switcher.css',
            [],
            $ver
        );
    }
    
    /**
 * Add language switcher to admin bar
 */
    public function admin_bar_menu($wp_admin_bar) {
        $languages = LF_Core::instance()->get_languages_for_switcher();

        // In admin, detect current language from lf_lang/lang URL param
        // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Read-only admin UI language routing, no data mutation.
        if (is_admin()) {
            if (!empty($_GET['lf_lang']) && isset($languages[$_GET['lf_lang']])) {
                $current_lang = sanitize_text_field(wp_unslash($_GET['lf_lang']));
            } elseif (!empty($_GET['lang']) && isset($languages[$_GET['lang']])) {
                $current_lang = sanitize_text_field(wp_unslash($_GET['lang']));
            } else {
                $current_lang = LF_Core::instance()->get_current_language();
            }
        } else {
            $current_lang = LF_Core::instance()->get_current_language();
        }
        $current = $languages[$current_lang] ?? reset($languages);

        // unified flag rendering — SVG when available, emoji fallback
        // otherwise. Prevents 404s (flags/.svg, flags/kk.svg, flags/vi.svg …)
        // from leaving a broken-image glyph next to the current language name.
        $current_flag_code = $current['flag'] ?? ($current['code'] ?? '');
        $wp_admin_bar->add_node([
            'id' => 'lf-language-switcher',
            'title' => LF_Core::instance()->flag_html_inline($current_flag_code, $current['native_name'] ?? '')
                     . esc_html($current['native_name']),
            'href' => '#',
        ]);

        // In admin post editor: resolve translations for correct links
        $admin_translations = [];
        if (is_admin()) {
            $screen = get_current_screen();
            if ($screen && $screen->base === 'post' && isset($_GET['post'])) {
                $post_id = intval($_GET['post']);
                $admin_translations = LF_Post_Translation::instance()->get_translations($post_id);
            }
        }
        // phpcs:enable WordPress.Security.NonceVerification.Recommended

        foreach ($languages as $code => $lang) {
            if ($code === $current_lang) continue;

            $href = $lang['url'];

            if (is_admin()) {
                if (!empty($admin_translations)) {
                    // Post editor: only show languages that have a translation
                    if (!isset($admin_translations[$code])) continue;
                    $href = admin_url('post.php?post=' . intval($admin_translations[$code]) . '&action=edit&lang=' . $code);
                } else {
                    // Non-post admin pages (options, settings, etc.): preserve current URL and add lf_lang
                    $base = set_url_scheme('http://' . sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'] ?? '')) . sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'] ?? '')));
                    $href = add_query_arg('lf_lang', $code, remove_query_arg(['lf_lang', 'lang'], $base));
                }
            }

            $lang_flag_code = $lang['flag'] ?? $code;
            $wp_admin_bar->add_node([
                'id' => 'lf-lang-' . $code,
                'parent' => 'lf-language-switcher',
                'title' => LF_Core::instance()->flag_html_inline($lang_flag_code, $lang['native_name'] ?? '')
                         . esc_html($lang['native_name']),
                'href' => $href,
            ]);
        }
    }
}

/**
 * Language Switcher Widget
 */
class LF_Language_Switcher_Widget extends WP_Widget {
    
    public function __construct() {
        parent::__construct(
            'lf_language_switcher',
            __('Language Switcher', 'langforge'),
            ['description' => __('Display language switcher', 'langforge')]
        );
    }
    
    public function widget($args, $instance) {
        echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted pre-built markup (theme widget wrapper)

        if (!empty($instance['title'])) {
            echo $args['before_title'] . apply_filters('widget_title', $instance['title']) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted pre-built markup (theme widget wrapper + core widget_title filter)
        }
        
        LF_Language_Switcher::instance()->render([
            'style' => $instance['style'] ?? 'dropdown',
            'show_flags' => $instance['show_flags'] ?? true,
            'show_names' => $instance['show_names'] ?? true,
            'show_current' => $instance['show_current'] ?? true,
        ]);
        
        echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted pre-built markup (theme widget wrapper)
    }

    public function form($instance) {
        $title = $instance['title'] ?? '';
        $style = $instance['style'] ?? 'dropdown';
        $show_flags = isset($instance['show_flags']) ? $instance['show_flags'] : true;
        $show_names = isset($instance['show_names']) ? $instance['show_names'] : true;
        $show_current = isset($instance['show_current']) ? $instance['show_current'] : true;
        ?>
        <p>
            <label for="<?php echo esc_attr($this->get_field_id('title')); ?>"><?php esc_html_e('Title:', 'langforge'); ?></label>
            <input class="widefat" id="<?php echo esc_attr($this->get_field_id('title')); ?>" name="<?php echo esc_attr($this->get_field_name('title')); ?>" type="text" value="<?php echo esc_attr($title); ?>">
        </p>
        <p>
            <label for="<?php echo esc_attr($this->get_field_id('style')); ?>"><?php esc_html_e('Style:', 'langforge'); ?></label>
            <select class="widefat" id="<?php echo esc_attr($this->get_field_id('style')); ?>" name="<?php echo esc_attr($this->get_field_name('style')); ?>">
                <option value="dropdown" <?php selected($style, 'dropdown'); ?>><?php esc_html_e('Dropdown', 'langforge'); ?></option>
                <option value="list" <?php selected($style, 'list'); ?>><?php esc_html_e('List', 'langforge'); ?></option>
                <option value="flags" <?php selected($style, 'flags'); ?>><?php esc_html_e('Flags only', 'langforge'); ?></option>
                <option value="plain" <?php selected($style, 'plain'); ?>><?php esc_html_e('Plain (unstyled)', 'langforge'); ?></option>
            </select>
        </p>
        <p>
            <input type="checkbox" id="<?php echo esc_attr($this->get_field_id('show_flags')); ?>" name="<?php echo esc_attr($this->get_field_name('show_flags')); ?>" value="1" <?php checked($show_flags); ?>>
            <label for="<?php echo esc_attr($this->get_field_id('show_flags')); ?>"><?php esc_html_e('Show flags', 'langforge'); ?></label>
        </p>
        <p>
            <input type="checkbox" id="<?php echo esc_attr($this->get_field_id('show_names')); ?>" name="<?php echo esc_attr($this->get_field_name('show_names')); ?>" value="1" <?php checked($show_names); ?>>
            <label for="<?php echo esc_attr($this->get_field_id('show_names')); ?>"><?php esc_html_e('Show language names', 'langforge'); ?></label>
        </p>
        <p>
            <input type="checkbox" id="<?php echo esc_attr($this->get_field_id('show_current')); ?>" name="<?php echo esc_attr($this->get_field_name('show_current')); ?>" value="1" <?php checked($show_current); ?>>
            <label for="<?php echo esc_attr($this->get_field_id('show_current')); ?>"><?php esc_html_e('Show current language in list', 'langforge'); ?></label>
        </p>
        <?php
    }
    
    public function update($new_instance, $old_instance) {
        $instance = [];
        $instance['title'] = sanitize_text_field($new_instance['title']);
        $instance['style'] = sanitize_text_field($new_instance['style']);
        $instance['show_flags'] = isset($new_instance['show_flags']);
        $instance['show_names'] = isset($new_instance['show_names']);
        $instance['show_current'] = isset($new_instance['show_current']);
        return $instance;
    }
}
