<?php
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
require_once( dirname( __FILE__ ) . '/smart-convert-currency-unit-conversion-geolocation.php' );

/**
 * Translates a `global-unit-*` catalog key (e.g. global-unit-fkp) using gettext.
 *
 * English source strings and msgctxt come from smart-convert-currency-unit-conversion-i18n-map.php
 * (generated from the translation CSV). Legacy non-catalog msgids may still resolve via .po parsing.
 *
 * @param string      $msgid Catalog key or legacy msgid.
 * @param string|null $locale Optional locale (uses switch_to_locale when provided).
 * @return string Localized string (may contain non-breaking spaces).
 */
function smart_convert_currency_unit_conversion_translate_global_unit_msgid( $msgid, $locale = null ) {
    if ( empty( $msgid ) ) {
        return '';
    }

    $msgid = trim( (string) $msgid );

    if ( strpos( $msgid, 'global-unit-' ) === 0 ) {
        $map = smart_convert_currency_unit_conversion_get_unit_catalog_english_map();
        if ( isset( $map[ $msgid ] ) ) {
            if ( null !== $locale && function_exists( 'switch_to_locale' ) ) {
                $locale_norm = str_replace( '-', '_', (string) $locale );
                $locale_norm = trim( $locale_norm );
                if ( $locale_norm !== '' ) {
                    $switched = switch_to_locale( $locale_norm );
                    $out      = smart_convert_currency_unit_conversion_translate_unit_catalog_key( $msgid );
                    if ( $switched ) {
                        restore_previous_locale();
                    }
                    return $out;
                }
            }
            return smart_convert_currency_unit_conversion_translate_unit_catalog_key( $msgid );
        }
    }

    $locale_to_use = null !== $locale ? (string) $locale : get_locale();
    $allowed       = array( (string) $msgid => true );
    $labels        = smart_convert_currency_unit_conversion_get_po_msgid_labels_filtered( $locale_to_use, $allowed );
    if ( isset( $labels[ (string) $msgid ] ) && $labels[ (string) $msgid ] !== '' ) {
        return (string) $labels[ (string) $msgid ];
    }

    $labels_en = smart_convert_currency_unit_conversion_get_po_msgid_labels_filtered( 'en_US', $allowed );
    if ( isset( $labels_en[ (string) $msgid ] ) && $labels_en[ (string) $msgid ] !== '' ) {
        return (string) $labels_en[ (string) $msgid ];
    }

    return '';
}

/**
 * Parses locale PO and returns translations for a filtered set of msgid values.
 *
 * @param string $locale
 * @param array<string,bool> $allowed_msgids
 * @return array<string,string> msgid => msgstr
 */
function smart_convert_currency_unit_conversion_get_po_msgid_labels_filtered( $locale, array $allowed_msgids ) {
    static $cache = array();
    $locale_norm = str_replace( '-', '_', (string) $locale );
    $locale_norm = trim( $locale_norm );
    if ( $locale_norm === '' ) {
        $locale_norm = 'en_US';
    }

    // Cache must be keyed by actual msgid list, otherwise results from a previous
    // call with a different msgid (but same count) can be reused incorrectly.
    $allowed_keys = array_keys( $allowed_msgids );
    sort( $allowed_keys );
    $cache_key = $locale_norm . '|' . count( $allowed_keys ) . '|' . md5( implode( '|', $allowed_keys ) );
    if ( isset( $cache[ $cache_key ] ) ) {
        return $cache[ $cache_key ];
    }

    $labels = array();
    if ( empty( $allowed_msgids ) ) {
        $cache[ $cache_key ] = $labels;
        return $labels;
    }

    $po_path = dirname( __DIR__ ) . '/languages/smart-convert-currency-unit-conversion-' . $locale_norm . '.po';
    if ( ! file_exists( $po_path ) ) {
        $cache[ $cache_key ] = $labels;
        return $labels;
    }

    $content = file_get_contents( $po_path );
    if ( ! is_string( $content ) || $content === '' ) {
        $cache[ $cache_key ] = $labels;
        return $labels;
    }

    $content = preg_replace( '/^\xEF\xBB\xBF/', '', $content );
    $lines = preg_split( "/\r\n|\n|\r/", $content );
    if ( ! is_array( $lines ) ) {
        $cache[ $cache_key ] = $labels;
        return $labels;
    }

    $msgid = null;
    $msgstr = null;
    $in_msgid = false;
    $in_msgstr = false;

    foreach ( $lines as $raw_line ) {
        $line = rtrim( (string) $raw_line, "\r" );

        if ( preg_match( '/^msgid "(.*)"$/', $line, $m ) ) {
            $msgid = stripcslashes( $m[1] );
            $msgstr = null;
            $in_msgid = true;
            $in_msgstr = false;
            continue;
        }

        if ( $in_msgid && preg_match( '/^"(.*)"$/', $line, $m ) ) {
            // Continuation line of msgid.
            $msgid .= stripcslashes( $m[1] );
            continue;
        }

        if ( preg_match( '/^msgstr "(.*)"$/', $line, $m ) ) {
            $msgstr = stripcslashes( $m[1] );
            $in_msgid = false;
            $in_msgstr = true;
            continue;
        }

        if ( $in_msgstr && preg_match( '/^"(.*)"$/', $line, $m ) ) {
            // Continuation line of msgstr.
            $msgstr .= stripcslashes( $m[1] );
            continue;
        }

        if ( $line === '' ) {
            if ( $msgid !== null && $msgstr !== null ) {
                if ( isset( $allowed_msgids[ $msgid ] ) && $msgstr !== '' ) {
                    $labels[ $msgid ] = $msgstr;
                }
            }
            $msgid = null;
            $msgstr = null;
            $in_msgid = false;
            $in_msgstr = false;
            continue;
        }
    }

    // Final commit (if file doesn't end with blank line)
    if ( $msgid !== null && $msgstr !== null ) {
        if ( isset( $allowed_msgids[ $msgid ] ) && $msgstr !== '' ) {
            $labels[ $msgid ] = $msgstr;
        }
    }

    $cache[ $cache_key ] = $labels;
    return $labels;
}

/**
 * Retrieves the translated name of a currency or unit from translation files.
 *
 * This function resolves a readable name from database definitions first.
 * If no record is found, it falls back to the uppercase code.
 *
 * @param string $code The currency or unit code (e.g., 'USD', 'km').
 * @return string The translated name (e.g., 'US Dollar'), or the uppercase code if translation is missing.
 */
function smart_convert_currency_unit_conversion_get_unit_name($code) {
    if (empty($code)) return '';
    
    $code_clean = trim( (string) sanitize_text_field( $code ) );
    $code_clean = preg_replace( '/[^A-Za-z0-9_-]/', '', $code_clean );
    $code_safe = strtolower( (string) $code_clean );
    if ( $code_safe === '' ) {
        return '';
    }
    $code_upper = strtoupper( $code_safe );

    $row_from = smart_convert_currency_unit_conversion_get_unit_definition_row( $code_safe, 'unit_from' );
    if ( is_array( $row_from ) && ! empty( $row_from['unit_from_name'] ) ) {
        $name_from = trim( (string) $row_from['unit_from_name'] );
        if ( $name_from !== '' && strcasecmp( $name_from, $code_safe ) !== 0 && strcasecmp( $name_from, $code_upper ) !== 0 ) {
            return $name_from;
        }
    }

    $row_to = smart_convert_currency_unit_conversion_get_unit_definition_row( $code_safe, 'unit_to' );
    if ( is_array( $row_to ) && ! empty( $row_to['unit_to_name'] ) ) {
        $name_to = trim( (string) $row_to['unit_to_name'] );
        if ( $name_to !== '' && strcasecmp( $name_to, $code_safe ) !== 0 && strcasecmp( $name_to, $code_upper ) !== 0 ) {
            return $name_to;
        }
    }

    // Built-in catalog: gettext _x( English from CSV, global-unit-<code>, domain ).
    $catalog_key = 'global-unit-' . $code_safe;
    $catalog_label = smart_convert_currency_unit_conversion_translate_unit_catalog_key( $catalog_key );
    if ( $catalog_label !== '' ) {
        return $catalog_label;
    }

    return $code_upper;
}

/**
 * Helper function to retrieve a unit definition row from the database with caching.
 * * This function replaces direct database queries to satisfy WordPress Plugin Check standards.
 *
 * @param string $code The unit code (e.g., 'kg', 'm').
 * @param string $col  The column to search by ('unit_from' or 'unit_to').
 * @return array|null  The database row or null if not found.
 */
function smart_convert_currency_unit_conversion_get_unit_definition_row($code, $col = 'unit_from') {
    global $wpdb;

    // Validate column name strictly using a whitelist logic.
    // We map the input strictly to a hardcoded string to ensure safe usage in SQL.
    $db_column = '';
    if ( 'unit_from' === $col ) {
        $db_column = 'unit_from';
    } elseif ( 'unit_to' === $col ) {
        $db_column = 'unit_to';
    } else {
        // Invalid column requested
        return null;
    }

    // Sanitize the input code (removes tags, trims, etc.) for general safety.
    $code_safe = sanitize_text_field($code);
    
    // Define cache key and group
    $cache_group = 'smart_convert_currency_unit_conversion';
    // Use the sanitized code and validated column for the cache key
    $cache_key   = 'smart_convert_currency_unit_conversion_unit_def_' . $db_column . '_' . $code_safe;

    // 1. Attempt to get from cache
    $cached_row = wp_cache_get($cache_key, $cache_group);

    if (false !== $cached_row) {
        return $cached_row;
    }

    // 2. If not in cache, query the database
    $table_name = $wpdb->prefix . 'smart_convert_currency_unit_conversion_units';
    $table_name_escaped = '`' . esc_sql( $table_name ) . '`';
    $db_column_escaped  = '`' . esc_sql( $db_column ) . '`';

    // Construct the SQL query carefully.
    // We use strict whitelisting for the column name above.
    // We nest prepare() directly inside get_row() to satisfy WP Plugin Check analysis
    // and prevent "Unescaped parameter" errors.
    
    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table and column identifiers are internal/whitelisted.
    $row = $wpdb->get_row( 
        $wpdb->prepare( "SELECT * FROM {$table_name_escaped} WHERE {$db_column_escaped} = %s LIMIT 1", $code_safe ),
        ARRAY_A 
    );

    // 3. Set cache (valid for 1 hour to reduce DB load)
    wp_cache_set($cache_key, $row, $cache_group, HOUR_IN_SECONDS);

    return $row;
}

/**
 * Helper function to handle pluralization of specific unit symbols.
 * * This function bridges the gap between static unit symbols (like 'kg') and 
 * words that require declension based on count (like 'days' vs 'day').
 * It utilizes the WordPress plural-forms API to handle plural forms correctly,
 * which is essential for languages with complex pluralization rules (e.g., Czech, Russian).
 *
 * @param string $key           The translation key from the DB (e.g., 'global-unit-symbol-day').
 * @param float  $count         The numerical value associated with the unit (determines singular/plural).
 * @param string $fallback_code Deprecated parameter kept for signature stability.
 * @return string The correctly pluralized and translated symbol or word.
 */
function smart_convert_currency_unit_conversion_translate_plural_symbol($key, $count, $fallback_code) {
    if (empty($key)) return '';

    // Use a switch statement to allow static string literals for WP Plugin Check compliance.
    // Dynamic plural calls with variables are flagged by PCP/PHPCS.
    switch ($key) {
        case 'global-unit-symbol-day':
            // translators: English: " d". Usage: Short symbol or abbreviation for the day (the localized abbreviation for day), localized according to local customs. It belongs to unit and currency management (defining, editing, or deleting) and displays directly next to numeric values on the public frontend where the Smart Convert shortcode renders conversion results. Condition: Shown directly as part of the conversion result seen by site visitors on the frontend. Variables: No dynamic placeholders. Linguistics: Standalone noun or abbreviation, typically not inflected. Constraints: Extremely short; prefer 1–3 characters so the layout of tables and inline results is not broken.
            return _n( '&nbsp;d', 'days', abs( (float) $count ), 'smart-convert-currency-unit-conversion' );
        
        case 'global-unit-symbol-week':
            // translators: English: " wk". Usage: Localized short symbol or abbreviation for the week ([týd.]), displayed directly next to numeric values in conversions. It belongs to unit and currency management (defining, editing, or deleting) and appears on the public frontend where the Smart Convert shortcode renders results. Condition: Shown directly as part of the conversion result seen by site visitors on the frontend. Variables: No dynamic placeholders. Linguistics: Standalone noun or abbreviation, typically not inflected. Constraints: Extremely short; prefer 1–3 characters so the layout of tables and inline results is not broken.
            return _n( '&nbsp;wk', 'weeks', abs( (float) $count ), 'smart-convert-currency-unit-conversion' );
        
        case 'global-unit-symbol-month':
            // translators: English: " mo". Usage: Localized short symbol or abbreviation for the month ([měs.]), displayed directly next to numeric values in conversions. It belongs to unit and currency management (defining, editing, or deleting) and appears on the public frontend where the Smart Convert shortcode renders results. Condition: Shown directly as part of the conversion result seen by site visitors on the frontend. Variables: No dynamic placeholders. Linguistics: Standalone noun or abbreviation, typically not inflected. Constraints: Extremely short; prefer 1–3 characters so the layout of tables and inline results is not broken.
            return _n( '&nbsp;mo', 'months', abs( (float) $count ), 'smart-convert-currency-unit-conversion' );
        
        case 'global-unit-symbol-year':
            // translators: English: " yr". Usage: Localized short symbol or abbreviation for the year ([year]), displayed directly next to numeric values in conversions. It belongs to unit and currency management (defining, editing, or deleting) and appears on the public frontend where the Smart Convert shortcode renders results. Condition: Shown directly as part of the conversion result seen by site visitors on the frontend. Variables: No dynamic placeholders. Linguistics: Standalone noun or abbreviation, typically not inflected. Constraints: Extremely short; prefer 1–3 characters so the layout of tables and inline results is not broken.
            return _n( '&nbsp;yr', 'years', abs( (float) $count ), 'smart-convert-currency-unit-conversion' );
        
        case 'global-unit-symbol-decade':
            // translators: English: " dec". Usage: Short symbol or abbreviation for the decade (the English term for decade), localized according to local customs. It belongs to unit and currency management (defining, editing, or deleting) and displays directly next to numeric values on the public frontend where the Smart Convert shortcode renders conversion results. Condition: Shown directly as part of the conversion result seen by site visitors on the frontend. Variables: No dynamic placeholders. Linguistics: Standalone noun or abbreviation, typically not inflected. Constraints: Extremely short; prefer 1–3 characters so the layout of tables and inline results is not broken.
            return _n( '&nbsp;dec', 'decades', abs( (float) $count ), 'smart-convert-currency-unit-conversion' );
        
        case 'global-unit-symbol-century':
            // translators: English: " c.". Usage: Short symbol or abbreviation for the century (the abbreviation for century), localized according to local customs. It belongs to unit and currency management (defining, editing, or deleting) and displays directly next to numeric values on the public frontend where the Smart Convert shortcode renders conversion results. Condition: Shown directly as part of the conversion result seen by site visitors on the frontend. Variables: No dynamic placeholders. Linguistics: Standalone noun or abbreviation, typically not inflected. Constraints: Extremely short; prefer 1–3 characters so the layout of tables and inline results is not broken.
            return _n( '&nbsp;c.', 'centuries', abs( (float) $count ), 'smart-convert-currency-unit-conversion' );
        
        case 'global-unit-symbol-cups':
            // translators: English: " cup". Usage: Short symbol or abbreviation for the cup (the localized term for the Cup unit), localized according to local customs. It belongs to unit and currency management (defining, editing, or deleting) and displays directly next to numeric values on the public frontend where the Smart Convert shortcode renders conversion results. Condition: Shown directly as part of the conversion result seen by site visitors on the frontend. Variables: No dynamic placeholders. Linguistics: Standalone noun or abbreviation, typically not inflected. Constraints: Extremely short; prefer 1–3 characters so the layout of tables and inline results is not broken.
            return _n( '&nbsp;cup', 'cups', abs( (float) $count ), 'smart-convert-currency-unit-conversion' );
        
        case 'global-unit-symbol-acre':
            // translators: English: " ac". Usage: Short symbol or abbreviation for the acre (the English name for acre), localized according to local customs. It belongs to unit and currency management (defining, editing, or deleting) and displays directly next to numeric values on the public frontend where the Smart Convert shortcode renders conversion results. Condition: Shown directly as part of the conversion result seen by site visitors on the frontend. Variables: No dynamic placeholders. Linguistics: Standalone noun or abbreviation, typically not inflected. Constraints: Extremely short; prefer 1–3 characters so the layout of tables and inline results is not broken.
            return _n( '&nbsp;ac', 'acres', abs( (float) $count ), 'smart-convert-currency-unit-conversion' );
        
        case 'global-unit-symbol-tbsp':
            // translators: English: " tbsp". Usage: Localized short symbol or abbreviation for the tablespoon ([lžíce]), displayed directly next to numeric values in conversions. It belongs to unit and currency management (defining, editing, or deleting) and appears on the public frontend where the Smart Convert shortcode renders results. Condition: Shown directly as part of the conversion result seen by site visitors on the frontend. Variables: No dynamic placeholders. Linguistics: Standalone noun or abbreviation, typically not inflected. Constraints: Extremely short; prefer 1–3 characters so the layout of tables and inline results is not broken.
            return _n( '&nbsp;tbsp', ' tbsp', abs( (float) $count ), 'smart-convert-currency-unit-conversion' );
        
        case 'global-unit-symbol-tsp':
            // translators: English: " tsp". Usage: Localized short symbol or abbreviation for the teaspoon ([lžička]), displayed directly next to numeric values in conversions. It belongs to unit and currency management (defining, editing, or deleting) and appears on the public frontend where the Smart Convert shortcode renders results. Condition: Shown directly as part of the conversion result seen by site visitors on the frontend. Variables: No dynamic placeholders. Linguistics: Standalone noun or abbreviation, typically not inflected. Constraints: Extremely short; prefer 1–3 characters so the layout of tables and inline results is not broken.
            return _n( '&nbsp;tsp', ' tsp', abs( (float) $count ), 'smart-convert-currency-unit-conversion' );
        
        default:
            return '';
    }
}

// === ASSET LOADING (Performance Optimized) ===

/**
 * Conditionally queues the assets to be printed in the footer.
 *
 * This function is called directly from the shortcode. It ensures that the 
 * expensive asset generation (CSS/JS) only happens if the shortcode is actually 
 * used on the page. It uses `wp_footer` to output the styles/scripts, which 
 * is more reliable than attaching inline styles to virtual handles.
 */
/**
 * Conditionally queues the assets to be printed in the footer.
 *
 * This function is called directly from the shortcode. It ensures that the 
 * expensive asset generation (CSS/JS) only happens if the shortcode is actually 
 * used on the page.
 */
function smart_convert_currency_unit_conversion_enqueue_assets_conditional() {
    // Static variable ensures we only hook/enqueue ONCE per page load,
    // even if multiple shortcodes are used on the same page.
    static $assets_hooked = false;
    
    if ( $assets_hooked ) {
        return;
    }
    
    // Load plugin configuration options safely
    $options = get_option('smart_convert_currency_unit_conversion_option_name', array());
    if (!is_array($options)) { $options = array(); }
    
    // Determine visual settings (Background and Text Color)
    $bg_color   = isset($options['smart_convert_currency_unit_conversion_bubble_color']) && !empty($options['smart_convert_currency_unit_conversion_bubble_color']) ? $options['smart_convert_currency_unit_conversion_bubble_color'] : '#424242';
    $text_color = isset($options['smart_convert_currency_unit_conversion_bubble_font']) && !empty($options['smart_convert_currency_unit_conversion_bubble_font']) ? $options['smart_convert_currency_unit_conversion_bubble_font'] : '#ffffff';

    // 1. Ensure Base Style is Loaded
    // This makes sure the static CSS file is present. If it was already loaded in head, this does nothing.
    wp_enqueue_style('smart-convert-currency-unit-conversion-shared-style');

    // 2. Register a VIRTUAL Handle for Dynamic CSS
    // We cannot attach inline styles to 'smart-convert-currency-unit-conversion-shared-style' here because
    // if that handle was already outputted in the <head>, WP will ignore new inline additions.
    // Using 'false' as src creates an inline-only style handle.
    wp_register_style( 'smart-convert-currency-unit-conversion-dynamic-style', false, array(), SMART_CONVERT_VERSION );
    
    $css_content = "
        .smart-convert-currency-unit-conversion-hover {
          position: relative;
          display: inline-block;
          border-bottom: 1px dotted black;
          cursor: help;
          white-space: nowrap;
        }

        .smart-convert-currency-unit-conversion-hover .smart-convert-currency-unit-conversion-bubble {
            display: none !important;
        }

        body > .smart-convert-currency-unit-conversion-bubble-clone {
            display: block !important;
            visibility: visible !important;
            opacity: 0;
            position: absolute;
            z-index: 100000;
            
            max-width: 16rem;
            background-color: " . esc_attr($bg_color) . ";
            color: " . esc_attr($text_color) . ";
            text-align: center;
            border-radius: 0.5rem;
            padding: 0.6rem 0.8rem;
            font-size: 0.85rem;
            line-height: 1.3;
            min-width: 12rem;
            box-shadow: 0 4px 15px rgba(0,0,0,0.25);
            pointer-events: none;
            transition: opacity 0.2s ease-in-out;
        }

        body > .smart-convert-currency-unit-conversion-bubble-clone strong {
            font-weight: 700;
            font-size: 1.35em;
            line-height: 1.1;
        }

        body > .smart-convert-currency-unit-conversion-bubble-clone strong + br {
            display: block;
            content: '';
            margin-top: 2px;
            margin-bottom: 2px;
            line-height: 0;
            height: 0;
        }
        
        body > .smart-convert-currency-unit-conversion-bubble-clone span {
            color: inherit; 
            opacity: 0.9;
            font-size: 0.75rem;
        }

        body > .smart-convert-currency-unit-conversion-bubble-clone::after {
          content: '';
          position: absolute;
          top: 100%;
          left: 50%;
          margin-left: -5px;
          border-width: 5px;
          border-style: solid;
          border-color: " . esc_attr($bg_color) . " transparent transparent transparent;
        }
    ";

    // Attach CSS to virtual handle and enqueue it (will print in footer)
    wp_add_inline_style('smart-convert-currency-unit-conversion-dynamic-style', $css_content);
    wp_enqueue_style('smart-convert-currency-unit-conversion-dynamic-style');

    // 3. Register a VIRTUAL Handle for Dynamic JS
    // We use a dummy handle because the script is purely inline.
    // Dependency 'jquery' ensures jQuery loads before this script runs.
    wp_register_script('smart-convert-currency-unit-conversion-dynamic-js', false, array('jquery'), SMART_CONVERT_VERSION, true);

    // 4. Generate and Add Inline JS
    $js_content = "
    jQuery(document).ready(function($) {
        $('.smart-convert-currency-unit-conversion-hover').on('mouseenter', function() {
            var \$source = $(this);
            var \$originalBubble = \$source.find('.smart-convert-currency-unit-conversion-bubble');
            
            if(\$originalBubble.length === 0) return;

            var \$clone = \$originalBubble.clone().addClass('smart-convert-currency-unit-conversion-bubble-clone');
            
            $('body').append(\$clone);
            
            var rect = \$source[0].getBoundingClientRect();
            var scrollY = window.scrollY || window.pageYOffset;
            var scrollX = window.scrollX || window.pageXOffset;
            
            \$clone.css({ visibility: 'hidden', display: 'block' });
            var bubbleH = \$clone.outerHeight();
            var bubbleW = \$clone.outerWidth();
            
            var top = rect.top + scrollY - bubbleH - 8;
            var left = rect.left + scrollX + (rect.width / 2) - (bubbleW / 2);
            
            \$clone.css({
                top: top,
                left: left,
                visibility: 'visible',
                opacity: 1
            });
            
            \$source.data('smart-convert-currency-unit-conversion-clone', \$clone);

        }).on('mouseleave', function() {
            var \$source = $(this);
            var \$clone = \$source.data('smart-convert-currency-unit-conversion-clone');
            
            if (\$clone) {
                \$clone.remove();
                \$source.removeData('smart-convert-currency-unit-conversion-clone');
            }
        });
    });
    ";

    // Attach JS to virtual handle and enqueue it
    wp_add_inline_script('smart-convert-currency-unit-conversion-dynamic-js', $js_content);
    wp_enqueue_script('smart-convert-currency-unit-conversion-dynamic-js');
    
    $assets_hooked = true;
}

/**
 * Outputs the CSS and JS directly into the footer.
 * * Uses wp_add_inline_style and wp_add_inline_script for proper enqueuing.
 */
function smart_convert_currency_unit_conversion_output_footer_assets() {

    // Load plugin configuration options safely
    $options = get_option('smart_convert_currency_unit_conversion_option_name', array());
    if (!is_array($options)) { $options = array(); }
    
    // Determine visual settings (Background and Text Color)
    $bg_color   = isset($options['smart_convert_currency_unit_conversion_bubble_color']) && !empty($options['smart_convert_currency_unit_conversion_bubble_color']) ? $options['smart_convert_currency_unit_conversion_bubble_color'] : '#424242';
    $text_color = isset($options['smart_convert_currency_unit_conversion_bubble_font']) && !empty($options['smart_convert_currency_unit_conversion_bubble_font']) ? $options['smart_convert_currency_unit_conversion_bubble_font'] : '#ffffff';

    // FIX: Enqueue the shared stylesheet that already exists
    // This ensures we have a valid handle to attach inline styles to
    wp_enqueue_style('smart-convert-currency-unit-conversion-shared-style');

    // 1. Generate CSS content
    $css_content = "
        .smart-convert-currency-unit-conversion-hover {
          position: relative;
          display: inline-block;
          border-bottom: 1px dotted black;
          cursor: help;
          white-space: nowrap;
        }

        .smart-convert-currency-unit-conversion-hover .smart-convert-currency-unit-conversion-bubble {
            display: none !important;
        }

        body > .smart-convert-currency-unit-conversion-bubble-clone {
            display: block !important;
            visibility: visible !important;
            opacity: 0;
            position: absolute;
            z-index: 100000;
            
            max-width: 16rem;
            background-color: " . esc_attr($bg_color) . ";
            color: " . esc_attr($text_color) . ";
            text-align: center;
            border-radius: 0.5rem;
            padding: 0.6rem 0.8rem;
            font-size: 0.85rem;
            line-height: 1.3;
            min-width: 12rem;
            box-shadow: 0 4px 15px rgba(0,0,0,0.25);
            pointer-events: none;
            transition: opacity 0.2s ease-in-out;
        }

        body > .smart-convert-currency-unit-conversion-bubble-clone strong {
            font-weight: 700;
            font-size: 1.35em;
            line-height: 1.1;
        }

        body > .smart-convert-currency-unit-conversion-bubble-clone strong + br {
            display: block;
            content: '';
            margin-top: 2px;
            margin-bottom: 2px;
            line-height: 0;
            height: 0;
        }
        
        body > .smart-convert-currency-unit-conversion-bubble-clone span {
            color: inherit; 
            opacity: 0.9;
            font-size: 0.75rem;
        }

        body > .smart-convert-currency-unit-conversion-bubble-clone::after {
          content: '';
          position: absolute;
          top: 100%;
          left: 50%;
          margin-left: -5px;
          border-width: 5px;
          border-style: solid;
          border-color: " . esc_attr($bg_color) . " transparent transparent transparent;
        }
    ";

    // Add inline CSS to the existing shared stylesheet handle
    wp_add_inline_style('smart-convert-currency-unit-conversion-shared-style', $css_content);

    // 2. Enqueue jQuery (dependency for our script)
    wp_enqueue_script('jquery');

    // Register a dummy handle for inline script
    wp_register_script('smart-convert-currency-unit-conversion-tooltip-inline-js', '', array('jquery'), SMART_CONVERT_VERSION, true);
    wp_enqueue_script('smart-convert-currency-unit-conversion-tooltip-inline-js');

    // 3. Generate JS content
    $js_content = "
    jQuery(document).ready(function($) {
        $('.smart-convert-currency-unit-conversion-hover').on('mouseenter', function() {
            var \$source = $(this);
            var \$originalBubble = \$source.find('.smart-convert-currency-unit-conversion-bubble');
            
            if(\$originalBubble.length === 0) return;

            var \$clone = \$originalBubble.clone().addClass('smart-convert-currency-unit-conversion-bubble-clone');
            
            $('body').append(\$clone);
            
            var rect = \$source[0].getBoundingClientRect();
            var scrollY = window.scrollY || window.pageYOffset;
            var scrollX = window.scrollX || window.pageXOffset;
            
            \$clone.css({ visibility: 'hidden', display: 'block' });
            var bubbleH = \$clone.outerHeight();
            var bubbleW = \$clone.outerWidth();
            
            var top = rect.top + scrollY - bubbleH - 8;
            var left = rect.left + scrollX + (rect.width / 2) - (bubbleW / 2);
            
            \$clone.css({
                top: top,
                left: left,
                visibility: 'visible',
                opacity: 1
            });
            
            \$source.data('smart-convert-currency-unit-conversion-clone', \$clone);

        }).on('mouseleave', function() {
            var \$source = $(this);
            var \$clone = \$source.data('smart-convert-currency-unit-conversion-clone');
            
            if (\$clone) {
                \$clone.remove();
                \$source.removeData('smart-convert-currency-unit-conversion-clone');
            }
        });
    });
    ";

    // Add inline JS to the dummy handle
    wp_add_inline_script('smart-convert-currency-unit-conversion-tooltip-inline-js', $js_content);
}


// === MAIN SHORTCODE FUNCTION ===
/**
 * Processes the [smart-convert] shortcode.
 *
 * Handles currency, unit, and temperature conversions. Supports auto-detection of
 * visitor currency via IP, applies bank spreads (fees), formats output with custom
 * or default templates, and generates interactive tooltips.
 *
 * @param array $atts User-defined attributes in the shortcode.
 * @return string HTML output of the converted value.
 */
function smart_convert_currency_unit_conversion_shortcode($atts) {

    // === PERFORMANCE: CONDITIONAL ASSET LOADING ===
    // Trigger the asset injection (footer hook) only when the shortcode is actually running.
    // This keeps the site lightweight on pages without conversions.
    smart_convert_currency_unit_conversion_enqueue_assets_conditional();

    // Retrieve global plugin options. 
    // FIX: Provide a default array to prevent false being passed to array_intersect_key
    $smart_convert_currency_unit_conversion_options = get_option('smart_convert_currency_unit_conversion_option_name', array());   
    
    // Defensive check: Ensure it is an array even if get_option returns something else unexpectedly
    if ( ! is_array( $smart_convert_currency_unit_conversion_options ) ) {
        $smart_convert_currency_unit_conversion_options = array();
    }

    // The 'spread' simulates a markup fee (e.g., 2%) on top of the mid-market exchange rate.
    // This allows site owners to display "Customer Rates" rather than "Interbank Rates".
    $smart_convert_currency_unit_conversion_spread = isset($smart_convert_currency_unit_conversion_options['smart_convert_currency_unit_conversion_spread']) ? (float)$smart_convert_currency_unit_conversion_options['smart_convert_currency_unit_conversion_spread'] : 0; 

    // Define keys for default configuration retrieval
    $default_currency_options = array(
        'smart_convert_currency_unit_conversion_date_format',
        'smart_convert_currency_unit_conversion_default_currency',
        'smart_convert_currency_unit_conversion_default_temperature',
        'smart_convert_currency_unit_conversion_default_length_long',
        'smart_convert_currency_unit_conversion_default_length_short',
        'smart_convert_currency_unit_conversion_default_speed',
        'smart_convert_currency_unit_conversion_default_distance',
        'smart_convert_currency_unit_conversion_default_weight',
        'smart_convert_currency_unit_conversion_default_area',
    );

    // Extract relevant default values for easy access
    $default_values = array_intersect_key($smart_convert_currency_unit_conversion_options, array_flip($default_currency_options));

    if (empty($smart_convert_currency_unit_conversion_spread)) {
        $smart_convert_currency_unit_conversion_spread = 0;
    }
    // Calculate spread multiplier (e.g., a 2% spread becomes a 1.02 multiplier)
    $spread = 1 + ($smart_convert_currency_unit_conversion_spread / 100);

    // Parse and normalize shortcode attributes
    $conversion = shortcode_atts(array(
        'from' => 'usd',
        'to' => '', 
        'amount' => '0',
        'decimals' => '', // Changed to empty string to enable smart default detection
        'output' => '', 
    ), $atts, 'smart-convert');
    
    // === INPUT SANITIZATION ===
    $conversion['from'] = sanitize_text_field( $conversion['from'] );
    $conversion['to']   = sanitize_text_field( $conversion['to'] );
    
    // Note on 'output': This attribute may contain complex HTML or custom strings.
    // We defer sanitization of 'output' to the very end (via wp_kses_post) to allow templates.
    $type2 = isset($atts['output']) && trim($atts['output']) !== '' ? $atts['output'] : $conversion['output'];
    
    $currfrom = $conversion['from'];
    $currto_provided = $conversion['to']; 
    $decimals = absint( $conversion['decimals'] ); // Ensure integer safety
    
    // Normalize amount input: remove spaces, convert commas to dots for float casting
    $amount_raw = sanitize_text_field( $conversion['amount'] ); 
    $original = str_replace([" ", ","], ["", "."], $amount_raw);

    // Map of default target units based on the input unit type.
    // Example: If input is 'km', logic suggests converting to 'mi' unless specified otherwise.
    $default_target_currency = array(
        'j. n. Y' => isset($default_values['smart_convert_currency_unit_conversion_date_format']) ? $default_values['smart_convert_currency_unit_conversion_date_format'] : '',
        'C' => isset($default_values['smart_convert_currency_unit_conversion_default_temperature']) ? $default_values['smart_convert_currency_unit_conversion_default_temperature'] : '',
        'F' => isset($default_values['smart_convert_currency_unit_conversion_default_temperature']) ? $default_values['smart_convert_currency_unit_conversion_default_temperature'] : '',
        'ft' => isset($default_values['smart_convert_currency_unit_conversion_default_length_long']) ? $default_values['smart_convert_currency_unit_conversion_default_length_long'] : '',
        'm' => isset($default_values['smart_convert_currency_unit_conversion_default_length_long']) ? $default_values['smart_convert_currency_unit_conversion_default_length_long'] : '',
        'km' => isset($default_values['smart_convert_currency_unit_conversion_default_distance']) ? $default_values['smart_convert_currency_unit_conversion_default_distance'] : '',
        'mi' => isset($default_values['smart_convert_currency_unit_conversion_default_distance']) ? $default_values['smart_convert_currency_unit_conversion_default_distance'] : '',
        'in' => isset($default_values['smart_convert_currency_unit_conversion_default_length_short']) ? $default_values['smart_convert_currency_unit_conversion_default_length_short'] : '',
        'cm' => isset($default_values['smart_convert_currency_unit_conversion_default_length_short']) ? $default_values['smart_convert_currency_unit_conversion_default_length_short'] : '',
        'mph' => isset($default_values['smart_convert_currency_unit_conversion_default_speed']) ? $default_values['smart_convert_currency_unit_conversion_default_speed'] : '',
        'kph' => isset($default_values['smart_convert_currency_unit_conversion_default_speed']) ? $default_values['smart_convert_currency_unit_conversion_default_speed'] : '',
        'lb' => isset($default_values['smart_convert_currency_unit_conversion_default_weight']) ? $default_values['smart_convert_currency_unit_conversion_default_weight'] : '',
        'kg' => isset($default_values['smart_convert_currency_unit_conversion_default_weight']) ? $default_values['smart_convert_currency_unit_conversion_default_weight'] : '',
        'sqkm' => isset($default_values['smart_convert_currency_unit_conversion_default_area']) ? $default_values['smart_convert_currency_unit_conversion_default_area'] : '',
        'sqmi' => isset($default_values['smart_convert_currency_unit_conversion_default_area']) ? $default_values['smart_convert_currency_unit_conversion_default_area'] : '',
    );

    // === TARGET CURRENCY DETERMINATION LOGIC ===
    // Priority 1: Use explicit 'to' parameter if provided in shortcode.
    if ( !empty($currto_provided) ) {
        $currto = $currto_provided;
    }
    // Priority 2: If 'to' is empty and IP Auto-Detection is enabled.
    elseif ( empty($currto_provided) ) {
        // Reuse the safe options array fetched earlier
        $auto_ip_enabled = isset($smart_convert_currency_unit_conversion_options['auto_currency_from_ip']) && $smart_convert_currency_unit_conversion_options['auto_currency_from_ip'] === '1';
        
        if ( $auto_ip_enabled ) {
            // Attempt to resolve currency from visitor's IP address
            $auto_currency = smart_convert_currency_unit_conversion_get_auto_currency_from_ip();
            if ( $auto_currency ) {
                $currto = $auto_currency;
            } else {
                // Fallback: IP detection failed, check default mapping map
                if ( isset($default_target_currency[$currfrom]) ) {
                    $currto = $default_target_currency[$currfrom];
                } else {
                    $currto = isset($default_values['smart_convert_currency_unit_conversion_default_currency']) ? $default_values['smart_convert_currency_unit_conversion_default_currency'] : '';
                }
            }
        } else {
            // Priority 3: Auto-detection disabled. Use default map or global default.
            if ( isset($default_target_currency[$currfrom]) ) {
                $currto = $default_target_currency[$currfrom];
            } else {
                $currto = isset($default_values['smart_convert_currency_unit_conversion_default_currency']) ? $default_values['smart_convert_currency_unit_conversion_default_currency'] : '';
            }
        }
    }
    
    // Initialize conversion type
    $type = null;

    // Sanitize again before database usage
    $currfrom_safe = sanitize_text_field($currfrom);
    $currto_safe = sanitize_text_field($currto);

    // === IDENTIFY CONVERSION TYPE & RETRIEVE RATES ===
    // Optimized with caching strategies to reduce DB load
    
    // 1. Check Temperature (Pure PHP logic, but checks DB for potential overrides/offsets)
    if (in_array($currfrom, ['C', 'F', 'K', 'R']) && in_array($currto, ['C', 'F', 'K', 'R'])) {
        $type = 'temperature';
        // Check units table for specific offsets using cached helper
        $row = smart_convert_currency_unit_conversion_get_unit_conversion_row($currfrom_safe, $currto_safe);
        
        $factor = $row && isset($row['factor']) ? (float)$row['factor'] : 1;
        $offset = $row && isset($row['offset']) ? (float)$row['offset'] : 0;
        $exchange_rate = $factor; 
    }
    else {
        // 2. Try Currency (Cached Lookup)
        // Optimization: Attempt to fetch the row immediately. If data exists, it is a currency.
        $currency_row = smart_convert_currency_unit_conversion_get_currency_rate_row($currfrom_safe, $currto_safe);

        if ($currency_row) {
            $type = 'currency';
            $exchange_rate = isset($currency_row['rate']) ? (float)$currency_row['rate'] : 1;
        } 
        else {
            // 3. Try Units (Cached Lookup)
            $unit_row = smart_convert_currency_unit_conversion_get_unit_conversion_row($currfrom_safe, $currto_safe);
            
            if ($unit_row) {
                $type = 'units';
                $exchange_rate = isset($unit_row['factor']) ? (float)$unit_row['factor'] : 1;
            } else {
                // 4. Fallback: Unknown type
                $type = 'unknown';
                $exchange_rate = 1;
            }
        }
    }
    
    // ==========================================================
    // CALCULATION PHASE
    // Note: Result is calculated before symbol lookup to facilitate pluralization logic.
    // ==========================================================
    
    // Apply Spread:
    // Logic: Spread is only applied to Currencies. Units (km -> mi) and Temps (C -> F) use raw factors.
    $exchange_rate_with_spread = ($currfrom == $currto) ? 1 : ($type === 'currency' ? $exchange_rate * $spread : $exchange_rate);
    
    // Perform Calculation
    if ($currfrom === "F" && $currto === "C") {
        // Fahrenheit to Celsius specific formula: (F - 32) * factor
        $original_fahrenheit = (float)$original - 32;
        $conversion2 = $original_fahrenheit * $exchange_rate;
    } else {
        // Standard Calculation: Amount * Rate
        $conversion2 = (float)$original * $exchange_rate_with_spread; 
    }
    // Celsius to Fahrenheit post-adjustment
    if ($currfrom === "C" && $currto === "F") {$conversion2 += 32;}


    // ==========================================================
    // SYMBOL RESOLUTION
    // ==========================================================

    // Initialize defaults
    $symbol_from_before = '';
    $symbol_from_after = '';
    $symbol_to_before = '';
    $symbol_to_after = '';
    $name_from = strtoupper($currfrom); // Default: Uppercase code
    $name_to = strtoupper($currto);   // Default: Uppercase code

    // Resolve Symbols based on Type (Utilizing Cache)
    if ($type === 'currency') {
        // Get FROM symbols (Self-join query cached)
        $row_from = smart_convert_currency_unit_conversion_get_currency_rate_row($currfrom_safe, $currfrom_safe);
        
        $symbol_from_before = (isset($row_from['symbol_before']) && $row_from['symbol_before'] !== '' && !is_numeric($row_from['symbol_before'])) ? trim($row_from['symbol_before']) : '';
        $symbol_from_after  = (isset($row_from['symbol_after'])  && $row_from['symbol_after']  !== '' && !is_numeric($row_from['symbol_after']))  ? trim($row_from['symbol_after'])  : '';

        // Get TO symbols
        $row_to = smart_convert_currency_unit_conversion_get_currency_rate_row($currto_safe, $currto_safe);
        
        $symbol_to_before = (isset($row_to['symbol_before']) && $row_to['symbol_before'] !== '' && !is_numeric($row_to['symbol_before'])) ? trim($row_to['symbol_before']) : '';
        $symbol_to_after  = (isset($row_to['symbol_after'])  && $row_to['symbol_after']  !== '' && !is_numeric($row_to['symbol_after']))  ? trim($row_to['symbol_after'])  : '';
    }

    if ($type === 'units' || $type === 'temperature') {
        // Get FROM symbols
        // 1. First, try to find a definition where this unit is the SOURCE (unit_from).
        // Uses cached helper function smart_convert_currency_unit_conversion_get_unit_definition_row to replace direct DB call.
        $row_from_source = smart_convert_currency_unit_conversion_get_unit_definition_row($currfrom_safe, 'unit_from');
        
        // --- A) CHECK CUSTOM COLUMNS (if they exist) ---
        if ($row_from_source && !empty($row_from_source['symbol_from_before'])) {
            $symbol_from_before = $row_from_source['symbol_from_before'];
        } else {
            $symbol_from_before = '';
        }

        $symbol_from_found = false;

        if ($row_from_source && !empty($row_from_source['symbol_from_after'])) {
            // If a specific 'symbol_from_after' is defined (Custom Unit), use it.
            $raw_symbol_from = $row_from_source['symbol_from_after'];
            // Check if it is a translation key or a static string
            $symbol_from_after = (strpos($raw_symbol_from, 'global-unit-symbol') !== false) 
                ? smart_convert_currency_unit_conversion_translate_plural_symbol($raw_symbol_from, $original, $currfrom) 
                : $raw_symbol_from;
            $symbol_from_found = true;
        } 
        
        // --- B) FALLBACK FOR STANDARD UNITS (LEGACY LOGIC) ---
        // If we didn't find a custom symbol, we must look for a row where this unit is the TARGET (unit_to).
        // Uses cached helper function smart_convert_currency_unit_conversion_get_unit_definition_row to replace direct DB call.
        if (!$symbol_from_found) {
            $row_from_target = smart_convert_currency_unit_conversion_get_unit_definition_row($currfrom_safe, 'unit_to');

            if ($row_from_target) {
                // We found a row where our unit is the TARGET. Read its 'symbol_after'.
                $raw_symbol_from = (isset($row_from_target['symbol_after']) && $row_from_target['symbol_after'] !== '' && !is_numeric($row_from_target['symbol_after'])) ? trim($row_from_target['symbol_after']) : '';
                $symbol_from_after = smart_convert_currency_unit_conversion_translate_plural_symbol($raw_symbol_from, $original, $currfrom);
            } else {
                // If the symbol is still not found, fallback to the plural translation of the code or empty.
                $symbol_from_after = smart_convert_currency_unit_conversion_translate_plural_symbol('', $original, $currfrom); 
            }
        }

        // Get TO symbols
        $row_to = smart_convert_currency_unit_conversion_get_unit_conversion_row($currto_safe, $currto_safe); 
        
        if (!$row_to) {
             // Fallback: look for unit definition as target
             // Uses cached helper function to replace direct DB call.
             $row_to = smart_convert_currency_unit_conversion_get_unit_definition_row($currto_safe, 'unit_to');
        }

        // --- CHECK FOR CUSTOM SYMBOLS IN DB (TO UNIT) ---
        if ($row_to && !empty($row_to['symbol_to_before'])) {
            $symbol_to_before = $row_to['symbol_to_before'];
        } else {
            $symbol_to_before = '';
        }

        if ($row_to && !empty($row_to['symbol_to_after'])) {
            $raw_symbol_to = $row_to['symbol_to_after'];
            $symbol_to_after = (strpos($raw_symbol_to, 'global-unit-symbol') !== false) 
                ? smart_convert_currency_unit_conversion_translate_plural_symbol($raw_symbol_to, $conversion2, $currto) 
                : $raw_symbol_to;
        } else {
            // Fallback
            $raw_symbol_to = (isset($row_to['symbol_after']) && $row_to['symbol_after'] !== '' && !is_numeric($row_to['symbol_after'])) ? trim($row_to['symbol_after']) : '';
            $symbol_to_after = smart_convert_currency_unit_conversion_translate_plural_symbol($raw_symbol_to, $conversion2, $currto);
        }
    }

    // Retrieve separators from settings
    $smart_convert_currency_unit_conversion_separator_thousands = isset($smart_convert_currency_unit_conversion_options['smart_convert_currency_unit_conversion_separator_thousands']) ? $smart_convert_currency_unit_conversion_options['smart_convert_currency_unit_conversion_separator_thousands'] : '';
    $smart_convert_currency_unit_conversion_separator_decimals = isset($smart_convert_currency_unit_conversion_options['smart_convert_currency_unit_conversion_separator_decimals']) ? $smart_convert_currency_unit_conversion_options['smart_convert_currency_unit_conversion_separator_decimals'] : '';

    
    // ==========================================================
    // LOGIC: SMART ROUNDING
    // Automatically determines the best number of decimal places
    // based on the context (Currency vs Unit) and magnitude of the value.
    // ==========================================================
    
    // 1. Check if the user explicitly provided 'decimals' in shortcode.
    $decimals_raw_input = isset($atts['decimals']) ? $atts['decimals'] : null;
    $decimals_was_explicit = ($decimals_raw_input !== null && $decimals_raw_input !== '');
    
    // 2. Initial Assumption: Use decimals provided by user or prepare for smart default.
    if ($decimals_was_explicit) {
        $final_decimals = (int) $conversion['decimals'];
    } else {
        // Will be determined by smart logic below
        $final_decimals = null;
    }

    // ADJUSTMENT: For currencies, if user explicitly asked for 1 decimal, force 2 (Standard accounting format).
    if ($type === 'currency' && $decimals_was_explicit && $final_decimals === 1) {
        $final_decimals = 2;
    }

    if ( !$decimals_was_explicit ) {
        // Apply Smart Default Rounding Logic
        
        if ($type === 'currency') {
            // A. Currencies
            // Rule: Whole numbers -> 0 decimals for clean display
            //       Large amounts (>= 100) with decimals -> 0 decimals (cleaner look).
            //       Medium amounts (>= 2) with decimals  -> 2 decimals (standard).
            //       Micro amounts (< 2)                  -> 3 decimals (precision for crypto/small values).
            if (floor($conversion2) == $conversion2) {
                // It's a whole number - no decimals needed
                $final_decimals = 0;
            } elseif ($conversion2 >= 100) {
                $final_decimals = 0; 
            } elseif ($conversion2 >= 2) {
                $final_decimals = 2; 
            } else {
                $final_decimals = 3; 
            }
        } 
        elseif ($type === 'temperature') {
             // B. Temperature: Usually presented as integers (e.g., 25°C).
            $final_decimals = 0; 
        }
        elseif ($type === 'units') {
            // C. Units: Smart default based on whether result is whole number
            // Whole numbers -> 0 decimals, decimal values -> 2 decimals
            if (floor($conversion2) == $conversion2) {
                $final_decimals = 0;
            } else {
                $final_decimals = 2;
            }
        }
        else {
            // Fallback for unknown types
            $final_decimals = 0; 
        }
    }

    // Apply formatting to calculated value
    $conversion_formatted = number_format($conversion2, $final_decimals, $smart_convert_currency_unit_conversion_separator_decimals, $smart_convert_currency_unit_conversion_separator_thousands);


    // If the value is positive but formatted as 0.00, we force higher precision.
        // We normalize the separator to dot for the float check.
        if ( $conversion2 > 0 && (float) str_replace( $smart_convert_currency_unit_conversion_separator_decimals, '.', $conversion_formatted ) == 0 ) {
            // Re-format with 12 decimals to show Satoshi/Wei values
            $conversion_formatted = number_format( $conversion2, 12, $smart_convert_currency_unit_conversion_separator_decimals, $smart_convert_currency_unit_conversion_separator_thousands );
    
            // Remove trailing zeros to keep it clean (e.g. 0.00005 instead of 0.00005000)
            if ( strpos( $conversion_formatted, $smart_convert_currency_unit_conversion_separator_decimals ) !== false ) {
                $conversion_formatted = rtrim( $conversion_formatted, '0' );
                $conversion_formatted = rtrim( $conversion_formatted, $smart_convert_currency_unit_conversion_separator_decimals );
            }
        }

    // ==========================================================
    // END OF SMART ROUNDING LOGIC
    // ==========================================================
    

    // Format the ORIGINAL (From) value input by user
    if (is_numeric($original)) {
        $original_string = (string)$original;
        
        // Detect original precision
        $original_float = (float)$original;
        
        if (strpos($original_string, '.') === false || $original_float == floor($original_float)) {
            // Integer - no decimals
            $decimals_original = 0;
        } else {
            // Has decimals - count them
            $decimals_original = strlen(substr(strrchr($original_string, '.'), 1));
        }
        
        // ADJUSTMENT: Ensure minimum 2 decimals for currency display consistency
        if ($type === 'currency' && $decimals_original === 1) {
            $decimals_original = 2;
        }
        
        $original_formatted = number_format($original_float, $decimals_original, $smart_convert_currency_unit_conversion_separator_decimals, $smart_convert_currency_unit_conversion_separator_thousands);
    } else {
        $original_formatted = esc_html($original); // Security escape if not numeric
    }


    // Prepare data variables for templates/macros
    $exchange_rate_text = '';
    $exchange_rate_date_formatted = '';
    $formatted_rate = '';
    $exchange_rate_used = $exchange_rate; // Base rate without spread
    

    if ($type === 'currency') {
        $smart_convert_currency_unit_conversion_date_format = isset($default_values['smart_convert_currency_unit_conversion_date_format']) ? $default_values['smart_convert_currency_unit_conversion_date_format'] : 'j. n. Y';
        
        // Use Cached Helper instead of direct DB call
        $currency_row = smart_convert_currency_unit_conversion_get_currency_rate_row($currfrom_safe, $currto_safe);
        
        $exchange_rate_used = isset($currency_row['rate']) ? $currency_row['rate'] : $exchange_rate; 
        $exchange_rate_date = isset($currency_row['updated_at']) ? $currency_row['updated_at'] : current_time('mysql');

        // --- DATA PREPARATION FOR TOOLTIP: DATE & RATE ---

        // Fetching update date specifically for display.
        // Convert codes to lowercase to match database keys.
        $from_db_case = strtolower($currfrom_safe);
        $to_db_case   = strtolower($currto_safe);

        $row_rate = smart_convert_currency_unit_conversion_get_currency_rate_row($from_db_case, $to_db_case); 
        
        // Date Retrieval and Localization
        if ($row_rate && !empty($row_rate['updated_at'])) {
            $exchange_rate_date_raw = $row_rate['updated_at']; // DB Timestamp
            
            // Determine date format preference (Plugin setting > WP Global setting)
            $date_format_option = isset($default_values['smart_convert_currency_unit_conversion_date_format']) && !empty($default_values['smart_convert_currency_unit_conversion_date_format']) 
                ? $default_values['smart_convert_currency_unit_conversion_date_format'] 
                : get_option('date_format');
                
            $timestamp = strtotime($exchange_rate_date_raw); 
            
            // Use wp_date for proper localization and timezone handling
            $exchange_rate_date_formatted = wp_date( $date_format_option, $timestamp );
        }
    }
        
    // --- TOOLTIP DATA FALLBACK & FORMATTING ---
    // Initialize date variable if not set
    if (!isset($exchange_rate_date_formatted)) {
        $exchange_rate_date_formatted = ''; 
    }
    
    // Prepare the display rate (incorporating spread if applicable)
    $exchange_rate_used = isset($exchange_rate_with_spread) ? $exchange_rate_with_spread : 1; 

    // Re-verification loop for Date (safety check for edge cases)
    if ($type === 'currency') {
        $row_rate = smart_convert_currency_unit_conversion_get_currency_rate_row($currfrom_safe, $currto_safe); 
        
        if ($row_rate && !empty($row_rate['updated_at'])) {
            $exchange_rate_date_raw = $row_rate['updated_at']; 
            
            $date_format_option = isset($default_values['smart_convert_currency_unit_conversion_date_format']) && !empty($default_values['smart_convert_currency_unit_conversion_date_format']) 
                ? $default_values['smart_convert_currency_unit_conversion_date_format'] 
                : get_option('date_format');
                
            $timestamp = strtotime($exchange_rate_date_raw); 
            $exchange_rate_date_formatted = wp_date( $date_format_option, $timestamp );
        }
    }
    // ----------------------------------------------------------------------------------

    // === RATE INFO GENERATION (Currency Only) ===
    $formatted_rate = number_format((float)$exchange_rate_used, 4, $smart_convert_currency_unit_conversion_separator_decimals, $smart_convert_currency_unit_conversion_separator_thousands);
    $exchange_rate_text = '';

    if ($type === 'currency') {
        // Load translated template for rate info
        // translators: English: "Converted using the exchange rate 1 %1$s = %2$s %3$s as of %4$s.". Usage: Frontend text displaying the applied exchange rate (e.g., "Converted at the rate 1 GEL = 121.5045 HUF as of 13. 12. 2025."). It belongs to exchange rate management and renders directly to site visitors within the conversion results. Variables include %1$s (source ISO code), %2$s (numeric rate), %3$s (target ISO code), and %4$s (formatted validity date). Keep this short noun phrase or sentence concise and readable.
        $exchange_rate_info = __(
            'Converted using the exchange rate 1&nbsp;%1$s&nbsp;=&nbsp;%2$s&nbsp;%3$s as of %4$s.',
            'smart-convert-currency-unit-conversion'
        );
        
        // Populate template: 1 USD = 23.50 CZK (Date)
        $exchange_rate_text = sprintf(
            $exchange_rate_info,
            strtoupper( $currfrom ),
            $formatted_rate, 
            strtoupper( $currto ),
            $exchange_rate_date_formatted
        );

        // === Spread Information Append ===
        // Adds text about bank fees/spread if enabled
        $show_spread_msg = isset($smart_convert_currency_unit_conversion_options['smart_convert_currency_unit_conversion_spread_msg_enable']) && $smart_convert_currency_unit_conversion_options['smart_convert_currency_unit_conversion_spread_msg_enable'] == '1';

        // Logic: Spread must be > 0 and message option enabled
        if ( $smart_convert_currency_unit_conversion_spread > 0 && $show_spread_msg ) {
            
            // 1. Normalize spread value
            $spread_value = (float) str_replace(',', '.', $smart_convert_currency_unit_conversion_spread);

            // 2. Format spread with max 2 decimals
            $formatted_spread = number_format($spread_value, 2, $smart_convert_currency_unit_conversion_separator_decimals, $smart_convert_currency_unit_conversion_separator_thousands);
            
            // 3. Trim insignificant trailing zeros
            $formatted_spread = rtrim(rtrim($formatted_spread, '0'), $smart_convert_currency_unit_conversion_separator_decimals);
            
            // Get template: "includes %s%% fee"
            // translators: English: "The exchange rate has been increased by %s %%, which simulates the actual rate used for card payments.". Usage: Informational frontend text indicating that the mid-market rate was increased by an admin-defined markup (bank margin). The translation must begin with a space, and %s %% (representing the dynamic markup percentage) must be retained. It belongs to the general settings and shared UI, rendering directly within conversion results to site visitors. Keep this declarative sentence concise.
            $spread_msg_template = __(
                ' The exchange rate has been increased by %s %%, which simulates the actual rate used for card payments.',
                'smart-convert-currency-unit-conversion'
            );
            
            // Append formatted spread message
            $exchange_rate_text .= sprintf( $spread_msg_template, $formatted_spread );
        }
    }
    // === END RATE INFO ===

    // === MACRO PREPARATION ===

    // Retrieve full localized names (e.g., "United States Dollar")
    $name_from = smart_convert_currency_unit_conversion_get_unit_name($currfrom);
    $name_to = smart_convert_currency_unit_conversion_get_unit_name($currto);
    
    // Construct {FROM} and {TO} strings inclusive of symbols
    $from_amount = $symbol_from_before . $original_formatted . $symbol_from_after;
    $to_amount   = $symbol_to_before . $conversion_formatted . $symbol_to_after;

    // Define Macro Placeholders
    $search = array(
        '{FROM}',
        '{TO}',
        '{FROM_VALUE}',
        '{TO_VALUE}',
        '{FROM_CODE}',
        '{TO_CODE}',
        '{FROM_NAME}',
        '{TO_NAME}',
        '{RATE_INFO}', // Empty for non-currencies
        '{RATE}', 
        '{DATE}',
    );

    // Define Replacement Values (escaped for safe HTML output per WordPress escaping guidelines)
    $replace = array(
        esc_html( $from_amount ),
        esc_html( $to_amount ),
        esc_html( $original_formatted ),
        esc_html( $conversion_formatted ),
        esc_html( strtoupper( $currfrom ) ),
        esc_html( strtoupper( $currto ) ),
        esc_html( $name_from ),
        esc_html( $name_to ),
        esc_html( $exchange_rate_text ),
        esc_html( $formatted_rate ),
        esc_html( $exchange_rate_date_formatted ),
    );
    
    // Default bubble/tooltip internal HTML (values escaped for safe output)
    $default_bubble_html = '<strong>' . esc_html( $to_amount ) . '</strong><br><span>' . esc_html( $exchange_rate_text ) . '</span>';


    // === OUTPUT FORMATTING & TEMPLATE HANDLING ===
    $custom_format_string = $type2; // Holds 'output' attribute (number or string)

// 1) Template Lookup: Check if output is a custom template key
if (!in_array($type2, ['1', '2', '3', '4', '5', '6'])) {
    // Attempt to load template by key
    $template = smart_convert_currency_unit_conversion_get_template_by_key($type2);
    
    if ($template) {
        // Use template string from database
        $custom_format_string = $template['template_output'];
    } else {
        // User-provided custom format string: sanitize to prevent XSS (allowed HTML only).
        $custom_format_string = wp_kses_post( $type2 );
    }
}

// 2) Legacy Mapping: Map numbers 1-6 to built-in templates
if (in_array($type2, ['1', '2', '3', '4', '5', '6'])) {
    $legacy_map = array(
        '1' => 'builtin_1',
        '2' => 'builtin_2',
        '3' => 'builtin_3',
        '4' => 'builtin_4',
        '5' => 'builtin_5',
        '6' => 'builtin_6'
    );
    
    $template_key = $legacy_map[$type2];
    $template = smart_convert_currency_unit_conversion_get_template_by_key($template_key);
    
    if ($template) {
        $custom_format_string = $template['template_output'];
    } else {
        // Fallback: Hardcoded legacy formats if DB templates are missing
        switch ($type2) {
            case '1':
                $custom_format_string = '{FROM} ({TO})';
                break;
            case '2':
                $custom_format_string = '{TO}';
                break;
            case '3':
                $custom_format_string = '{FROM}';
                break;
            case '4':
                $custom_format_string = '||{FROM}##<strong>{TO}</strong><br>{RATE_INFO}##||';
                break;
            case '5':
                $custom_format_string = '{FROM}<br>||{TO}##<strong>{TO}</strong><br>{RATE_INFO}##||';
                break;
            case '6':
                $custom_format_string = '||{TO}##<strong>{FROM}</strong><br>{RATE_INFO}##||';
                break;
        }
    }
}

// 3) Default Fallback: If output is empty or generic, load type-specific default
if (empty($custom_format_string) || $custom_format_string === '4') {
    if ($type === 'currency') {
        $default_template = smart_convert_currency_unit_conversion_get_default_currency_template();
    } else {
        $default_template = smart_convert_currency_unit_conversion_get_default_units_template();
    }
    
    if ($default_template) {
        $custom_format_string = $default_template['template_output'];
    } else {
        // Ultimate hardcoded fallback
        $custom_format_string = '||{FROM}##<strong>{TO}</strong><br>{RATE_INFO}##||';
    }
}
    
    // Cleanup: If not currency, remove tooltip delimiters (|| and ##) to prevent UI clutter
    if ($type !== 'currency') {
        $custom_format_string = str_replace(['||', '||'], '', $custom_format_string);
        $custom_format_string = str_replace(['##', '##'], '', $custom_format_string);
    }

    // === FINAL STRING PROCESSING ===

    // 1. Perform Macro Replacement
    // Replaces {FROM}, {TO}, etc. with actual values
    $output = str_replace($search, $replace, $custom_format_string);

    // 2. Tooltip Generation via Regex (Parsing ||...|| delimiters)
    // Only processed for currencies to enable hover effects
    if ($type === 'currency') {
        // Regex captures text between || markers. 's' modifier allows matching across newlines.
        
        // Prepare data array for closure use
        $data_for_tooltip = [
            'from'     => $from_amount,
            'to'       => $to_amount,
            'rate'     => number_format((float)$exchange_rate_with_spread, 4, '.', ''), // Raw for JS
            'date'     => $exchange_rate_date_formatted,
            'currfrom' => strtoupper($currfrom),
            'currto'   => strtoupper($currto),
            'info'     => $exchange_rate_text,
        ];
        
        // Process tooltip delimiters
        $output = preg_replace_callback(
            '/\s*\|\|(.*?)\|\|\s*/s', 
            function($matches) use ($data_for_tooltip, $default_bubble_html) {
                
                $full_content = $matches[1];
                $visible_content = $full_content;
                $bubble_content_html = ''; 
                
                // Check for nested ##...## delimiters (indicates Custom Bubble Content)
                if (preg_match('/\s*##(.*?)##\s*/s', $full_content, $bubble_matches)) {
                    // Extract custom bubble content and sanitize for safe HTML output
                    $bubble_content = trim($bubble_matches[1]);
                    $bubble_content_html = '<span class="smart-convert-currency-unit-conversion-bubble">' . wp_kses_post( $bubble_content ) . '</span>';
                    // Remove the bubble definition from the visible text trigger
                    $visible_content = str_replace($bubble_matches[0], '', $full_content);
                } else {
                    // No custom content found, use default bubble HTML
                    $bubble_content_html = '<span class="smart-convert-currency-unit-conversion-bubble">' . $default_bubble_html . '</span>';
                }

                // Generate HTML data-attributes for JavaScript interaction
                $data_attributes = "data-from='" . esc_attr($data_for_tooltip['from']) . "' " .
                                   "data-to='" . esc_attr($data_for_tooltip['to']) . "' " .
                                   "data-rate='" . esc_attr($data_for_tooltip['rate']) . "' " .
                                   "data-date='" . esc_attr($data_for_tooltip['date']) . "' " .
                                   "data-currfrom='" . esc_attr($data_for_tooltip['currfrom']) . "' " .
                                   "data-currto='" . esc_attr($data_for_tooltip['currto']) . "' " .
                                   "data-info='" . esc_attr($data_for_tooltip['info']) . "'";

                // Return valid HTML: visible content sanitized to prevent XSS from user-provided format strings
                return '<span class="smart-convert-currency-unit-conversion-hover" ' . $data_attributes . '>' . wp_kses_post( trim( $visible_content ) ) . $bubble_content_html . '</span>';
            },
            $output
        );
    }
    
    // Optimization: Identical currency bypass (USD -> USD)
    // If source and target are the same, skip conversion UI and return formatted amount.
    if ($currfrom == $currto) {
         return wp_kses_post( $to_amount );
    }
    
    // Final Output Sanitization
    return wp_kses_post( $output );
}
add_shortcode( 'smart-convert', 'smart_convert_currency_unit_conversion_shortcode' );



/**
 * Prepares template data for use in JavaScript editors (Gutenberg/Classic).
 * * Aggregates all available templates and identifies defaults for currencies and units.
 *
 * @return array structured data for JS localization.
 */
function smart_convert_currency_unit_conversion_get_templates_for_js() {
    $templates = smart_convert_currency_unit_conversion_get_all_templates();
    $default_currency = smart_convert_currency_unit_conversion_get_default_currency_template();
    $default_units = smart_convert_currency_unit_conversion_get_default_units_template();
    
    return array(
        'templates' => array_map(function($t) {
            return array(
                'key' => $t['template_key'],
                'name' => $t['template_name'],
                'output' => $t['template_output'],
                'description' => $t['template_description'],
                'type' => $t['template_type'],
                'isDefaultCurrency' => ($t['is_default_currency'] == 1),
                'isDefaultUnits' => ($t['is_default_units'] == 1)
            );
        }, $templates),
        'defaultCurrencyKey' => $default_currency ? $default_currency['template_key'] : 'builtin_4',
        'defaultUnitsKey' => $default_units ? $default_units['template_key'] : 'builtin_4'
    );
}




// === GUTENBERG BLOCK REGISTRATION ===
add_action( 'init', 'smart_convert_currency_unit_conversion_register_convert_block' );

/**
 * Registers the 'smart-convert-currency-unit-conversion/convert' Gutenberg block.
 *
 * Enqueues the necessary block editor scripts, handles localization,
 * and sets up the server-side render callback.
 */
function smart_convert_currency_unit_conversion_register_convert_block() {
    if ( ! function_exists( 'register_block_type' ) ) {
        return;
    }

    wp_register_script(
        'smart-convert-currency-unit-conversion-block',
        SMART_CONVERT_PLUGIN_URL . '/smart-convert-currency-unit-conversion-block.js',
        array(
            'wp-blocks',
            'wp-element',
            'wp-i18n',
            'wp-block-editor',
            'wp-components',
            'wp-server-side-render',
        ),
        SMART_CONVERT_VERSION,
        true
    );
    
    // === Localize templates data for the block editor ===
    wp_localize_script(
        'smart-convert-currency-unit-conversion-block',
        'SmartConvertCurrencyUnitConversionTemplates',
        smart_convert_currency_unit_conversion_get_templates_for_js()
    );

    if (function_exists('wp_set_script_translations')) {
    wp_set_script_translations(
        'smart-convert-currency-unit-conversion-block',
        'smart-convert-currency-unit-conversion',
        plugin_dir_path(dirname(__FILE__)) . '/languages'
    );
}

    register_block_type(
        'smart-convert-currency-unit-conversion/convert',
        array(
            'editor_script'   => 'smart-convert-currency-unit-conversion-block',
            'render_callback' => 'smart_convert_currency_unit_conversion_render_convert_block',
            'attributes'      => array(
                'amount'   => array(
                    'type'    => 'string',
                    'default' => '1',
                ),
                'from'     => array(
                    'type'    => 'string',
                    'default' => 'USD',
                ),
                'to'       => array(
                    'type'    => 'string',
                    'default' => '',
                ),
                'decimals' => array(
                    'type'    => 'string',
                    'default' => '0',
                ),
                'output'   => array(
                    'type'    => 'string',
                    'default' => '',
                ),
            ),
        )
    );
}

/**
 * Render callback for the Gutenberg block.
 * * Bridges the Block Editor to the main Shortcode logic. This ensures that
 * the block renders exactly the same way as the [smart-convert] shortcode on the frontend.
 *
 * @param array $attributes Block attributes.
 * @return string HTML output.
 */
function smart_convert_currency_unit_conversion_render_convert_block( $attributes ) {
	if ( ! function_exists( 'smart_convert_currency_unit_conversion_shortcode' ) ) {
		return '';
	}

	// Prepare attributes (Output matches the 'output' attribute of the shortcode)
    // Default to empty to ensure consistency with shortcode logic
	$atts = array(
		'amount'   => isset( $attributes['amount'] ) ? $attributes['amount'] : '1',
		'from'     => isset( $attributes['from'] ) ? $attributes['from'] : 'USD',
		'to'       => isset( $attributes['to'] ) ? $attributes['to'] : '',
		'decimals' => isset( $attributes['decimals'] ) ? $attributes['decimals'] : '0',
		'output'   => isset( $attributes['output'] ) ? $attributes['output'] : '',
	);

	return smart_convert_currency_unit_conversion_shortcode( $atts );
}

/**
 * Registers an inline format tool (Toolbar button) for the Classic Editor/TinyMCE.
 * Allows easy insertion of [smart-convert] shortcodes within standard text blocks.
 */
add_action( 'enqueue_block_editor_assets', 'smart_convert_currency_unit_conversion_register_inline_convert_format' );

function smart_convert_currency_unit_conversion_register_inline_convert_format() {
    wp_enqueue_script(
        'smart-convert-currency-unit-conversion-inline',
        SMART_CONVERT_PLUGIN_URL . '/smart-convert-currency-unit-conversion-inline.js',
        array(
            'wp-rich-text',
            'wp-element',
            'wp-components',
            'wp-block-editor',
            'wp-i18n',
        ),
        SMART_CONVERT_VERSION,
        true
    );

    $default_currency = get_option( 'smart_convert_currency_unit_conversion_default_currency', 'USD' );

    // === Add templates data and settings ===
    $localize_data = array_merge(
        array('defaultCurrency' => $default_currency),
        smart_convert_currency_unit_conversion_get_templates_for_js()
    );

    wp_localize_script(
        'smart-convert-currency-unit-conversion-inline',
        'SmartConvertCurrencyUnitConversionSettings',
        $localize_data
    );

    wp_set_script_translations(
        'smart-convert-currency-unit-conversion-inline',
        'smart-convert-currency-unit-conversion',
        SMART_CONVERT_PLUGIN_DIR . '/languages'
    );

    // Regional locale fallback for script JSON translations (e.g. fr_BE -> fr_FR).
    $inline_locale = function_exists( 'determine_locale' ) ? determine_locale() : get_locale();
    if ( is_string( $inline_locale ) && '' !== $inline_locale && false !== strpos( $inline_locale, '_' ) ) {
        $lang = strtolower( strtok( $inline_locale, '_' ) );
        if ( '' !== $lang ) {
            $json_matches = glob( SMART_CONVERT_PLUGIN_DIR . '/languages/smart-convert-currency-unit-conversion-' . $lang . '_*-smart-convert-currency-unit-conversion-inline.json' );
            if ( is_array( $json_matches ) && ! empty( $json_matches ) ) {
                sort( $json_matches, SORT_NATURAL | SORT_FLAG_CASE );
                $fallback_json_path = $json_matches[0];
                $fallback_json_body = file_get_contents( $fallback_json_path );
                if ( is_string( $fallback_json_body ) && '' !== $fallback_json_body ) {
                    $fallback_json_body = preg_replace( '/^\xEF\xBB\xBF/', '', $fallback_json_body );
                    $fallback_decoded   = json_decode( $fallback_json_body, true );
                    if ( is_array( $fallback_decoded ) && isset( $fallback_decoded['locale_data']['smart-convert-currency-unit-conversion'] ) ) {
                        $fallback_data = $fallback_decoded['locale_data']['smart-convert-currency-unit-conversion'];
                        if ( isset( $fallback_data[''] ) && is_array( $fallback_data[''] ) ) {
                            $fallback_data['']['lang'] = $inline_locale;
                        }
                        wp_add_inline_script(
                            'smart-convert-currency-unit-conversion-inline',
                            'wp.i18n.setLocaleData(' . wp_json_encode( $fallback_data ) . ',"smart-convert-currency-unit-conversion");',
                            'before'
                        );
                    }
                }
            }
        }
    }
}
?>