<?php

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

use Ticketack\WP\TKTApp;
use Ticketack\WP\Helpers\SyncHelper;
use ScssPhp\ScssPhp\Compiler;
use ScssPhp\ScssPhp\ValueConverter;

/**
 * Utils functions
 */

/**
 * Extract url param
 *•
 * @param string $key: The param name
 * @param mixed $default: The default value if the url param is not found
 *
 * @return mixed: The URL param if found, $default otherwise
 */
function tkt_get_url_param($key, $default = null)
{
    return array_key_exists($key, $_GET) ? sanitize_text_field($_GET[$key]) : $default;
}

/**
 * Formats a DateTime in a full date and time format
 *
 * @param $dt
 *   The DateTime object to format.
 *
 * @return
 *   A string.
 */
function tkt_datetime_to_s($dt)
{
    $fmt = "j F Y H:i";
    return wp_date($fmt, $dt->getTimestamp());
}

/**
 * Formats a DateTime in a full date format
 *
 * @param $dt
 *   The DateTime object to format.
 *
 * @return
 *   A string.
 */
function tkt_date_to_s($dt)
{
    $fmt = "j F Y";
    return wp_date($fmt, $dt->getTimestamp());
}

/**
 * Formats a DateTime in a minimal date format
 *
 * @param $dt
 *   The DateTime object to format.
 *
 * @return
 *   A string.
 */
function tkt_date_to_min_s($dt)
{
    $fmt = "j F";
    return wp_date($fmt, $dt->getTimestamp());
}

/**
 * Formats a DateTime in a minimal date and time format
 *
 * @param $dt
 *   The DateTime object to format.
 *
 * @return
 *   A string.
 */
function tkt_date_and_time_to_min_s($dt)
{
    $fmt = "j F H:i";
    return wp_date($fmt, $dt->getTimestamp());
}

/**
 * Formats a DateTime in a hour format
 *
 * @param $dt
 *   The DateTime object to format.
 *
 * @return
 *   A string.
 */
function tkt_date_and_time_to_time_s($dt)
{
    $fmt = "H:i";
    return wp_date($fmt, $dt->getTimestamp());
}

/**
 * convert an ISO-8601 formated string to a PHP DateTime object.
 *
 * see http://stackoverflow.com/questions/14849446/php-parse-date-in-iso-format
 *
 * @bugs
 *   Milliseconds will be lost.
 *
 * @return
 *   A DateTime object or false on error.
 */
function tkt_iso8601_to_datetime($str)
{
    $i = strtotime($str);
    $d = new \DateTime();
    return $d->setTimestamp($i);
}

/**
 * convert a PHP DateTime object to an ISO-8601 string
 *
 * @see
 *   http://php.net/manual/en/class.datetime.php#datetime.constants.iso8601
 *
 * @return
 *   A string.
 */
function tkt_datetime_to_iso8601($d)
{
    return $d->format(\DateTime::ATOM);
}

/**
 * Get a plugin asset url
 *
 * @param string $path: The file path, relative to plugin root dir
 *
 * @return string
 */
function tkt_assets_url($path)
{
    return plugin_dir_url( TKT_APP ) . 'front/' . $path . '?v=' . TKT_ASSETS_VERSION;

}

/**
 * Get a link to a page by its slug, in the current language
 *
 * @param string $slug in the default language
 * @param string $query
 *
 * @return string
 */
function tkt_page_url($slug, $query = "")
{
    $url = get_site_url(/*$blog_id*/null, $slug);

    if (TKT_WPML_INSTALLED) {
        // get the page in default language
        $excluded_types = ['tkt-event', 'post', 'tkt-article'];
        $post_types     = array_diff(get_post_types(), $excluded_types);
        $page           = get_page_by_path($slug, OBJECT, $post_types);

        if ($page) {
            $pageId = $page->ID;
            if (tkt_current_lang() != tkt_default_lang()) {
                // get the slug in current language
                $post_type = get_post_type($page->ID);
                $pageId = tkt_translated_id_by_id($page->ID, $post_type, tkt_current_lang(), $slug);
            }

            $url = apply_filters('wpml_permalink', get_permalink($pageId));
        }
    }

    return sprintf('%s%s', $url, (!empty($query) ? '?'.$query : ''));
}

/**
 * Get the Program page url
 *
 * @param string $query
 *
 * @return string
 */
function tkt_program_url($query = "")
{
    $slug = TKTApp::get_instance()->get_config('pages.program');
    return $slug ? tkt_page_url($slug, $query) : null;
}

/**
 * Get the Ticket View page url
 *
 * @param string $query
 *
 * @return string
 */
function tkt_ticket_view_url($query = "")
{
    $slug = TKTApp::get_instance()->get_config('pages.ticket_view');
    return $slug ? tkt_page_url($slug, $query) : null;
}

/**
 * Get the Shop page url
 *
 * @param string $query
 *
 * @return string
 */
function tkt_shop_url($query = "")
{
    $slug = TKTApp::get_instance()->get_config('pages.shop');
    return $slug ? tkt_page_url($slug, $query) : null;
}

/**
 * Get the Cart page url
 *
 * @param string $query
 *
 * @return string
 */
function tkt_cart_url($query = "")
{
    $slug = TKTApp::get_instance()->get_config('pages.cart');
    return $slug ? tkt_page_url($slug, $query) : null;
}

/**
 * Get the Checkout page url
 *
 * @param string $query
 *
 * @return string
 */
function tkt_checkout_url($query = "")
{
    $slug = TKTApp::get_instance()->get_config('pages.checkout');
    return $slug ? tkt_page_url($slug, $query) : null;
}

/**
 * Get the Thank you page url
 *
 * @param string $query
 *
 * @return string
 */
function tkt_thank_you_url($query = "")
{
    $slug = TKTApp::get_instance()->get_config('pages.thank_you');
    return $slug ? tkt_page_url($slug, $query) : null;
}

/**
 * Get the eshop buy pass page url
 *
 * @return string
 */
function tkt_buy_pass_url($query = "")
{
    $slug = TKTApp::get_instance()->get_config('pages.pass');
    return $slug ? tkt_page_url($slug, $query) : null;
}

/**
 * Get the Cart page url
 *
 * @return string
 */
function tkt_cart_reset_url()
{
    return sprintf(
        "%s/cart/reset",
        TKTApp::get_instance()->get_config('ticketack.eshop_uri')
    );
}

/**
 * Get an event details url
 *
 * @param Event $event
 *
 * @return string
 */
function tkt_event_details_url($event)
{
    if (TKT_WPML_INSTALLED) {
        $slug = tkt_get_event_slug($event, TKT_LANG);
        $page = get_page_by_path($slug, OBJECT, 'tkt-event');
        return apply_filters('wpml_permalink', get_permalink($page->ID));
    }

    return get_site_url(
        /*$blog_id*/null,
        sprintf(
            '%s/%s',
            'events',
          tkt_get_event_slug($event, TKT_LANG)
        )
    );
}

/**
 * Get an event book url
 *
 * @param Event $event
 * @param Screening $screening: pre-selected screening
 *
 * @return string
 */
function tkt_event_book_url($event, $screening = null)
{
    if (TKT_WPML_INSTALLED) {
        $slug = tkt_get_event_slug($event, TKT_LANG);
        $page = get_page_by_path($slug, OBJECT, 'tkt-event');

        if (!$page) {
            return null;
        }

        return sprintf(
            "%s?book=1%s",
            apply_filters('wpml_permalink', get_permalink($page->ID)),
            (!is_null($screening) ? '&s_id='.$screening->_id() : '')
        );
    }

    return get_site_url(
        /*$blog_id*/null,
        sprintf(
            "%s/%s/?book=1%s",
            'events',
        tkt_get_event_slug($event, TKT_LANG),
            (!is_null($screening) ? '&s_id='.$screening->_id() : '')
        )
    );
}

/**
 * Get an article details url
 *
 * @param Article $article
 *
 * @return string
 */
function tkt_article_details_url($article)
{
    if (TKT_WPML_INSTALLED) {
        $slug = tkt_get_article_slug($article, TKT_LANG);
        $page = get_page_by_path($slug, OBJECT, 'tkt-article');
        if ($page) {
            return apply_filters('wpml_permalink', get_permalink($page->ID));
        }
    }

    return get_site_url(
        /*$blog_id*/null,
        sprintf(
            '%s/%s',
            'articles',
          tkt_get_article_slug($article, TKT_LANG)
        )
    );
}

/**
 * Get the login page url
 *
 * @param string $query
 *
 * @return string
 */
function tkt_login_url($query = "")
{
    $slug = TKTApp::get_instance()->get_config('pages.login');
    return $slug ? tkt_page_url($slug, $query) : null;
}

/**
 * Get the registration page url
 *
 * @param string $query
 *
 * @return string
 */
function tkt_registration_url($query = "")
{
    $slug = TKTApp::get_instance()->get_config('pages.registration');
    return $slug ? tkt_page_url($slug, $query) : null;
}

/**
 * Get the lost password page url
 *
 * @param string $query
 *
 * @return string
 */
function tkt_lostpassword_url($query = "")
{
    $slug = TKTApp::get_instance()->get_config('pages.lostpassword');
    return $slug ? tkt_page_url($slug, $query) : null;
}

/**
 * Get the change password page url
 *
 * @param string $query
 *
 * @return string
 */
function tkt_changepassword_url($query = "")
{
    $slug = TKTApp::get_instance()->get_config('pages.changepassword');
    return $slug ? tkt_page_url($slug, $query) : null;
}

/**
 * Get the user account page url
 *
 * @param string $query
 *
 * @return string
 */
function tkt_user_account_url($query = "")
{
    $slug = TKTApp::get_instance()->get_config('pages.account');
    return $slug ? tkt_page_url($slug, $query) : null;
}

/**
 * Get the Terms conditions page url
 *
 * @return string
 */
function tkt_terms_conditions_url()
{
    $eshop_config = TKTApp::get_instance()->get_config('eshop');
    $url          = $eshop_config["url_overrides"]["terms_conditions_url"][TKT_LANG] ?? null;

    if (empty($url)) {
        $url = sprintf(
            "%s/legal/terms?lang=%s",
            TKTApp::get_instance()->get_config('ticketack.eshop_uri'),
            TKT_LANG
        );
    }

    return $url;
}

/**
 * Get the Privacy policy page url
 *
 * @return string
 */
function tkt_privacy_policy_url()
{
    $eshop_config = TKTApp::get_instance()->get_config('eshop');
    $url          = $eshop_config["url_overrides"]["privacy_policy_url"][TKT_LANG] ?? null;

    if (empty($url)) {
        $url = sprintf(
            "%s/legal/privacy?lang=%s",
            TKTApp::get_instance()->get_config('ticketack.eshop_uri'),
            TKT_LANG
        );
    }

    return $url;
}

/**
 * Get the Sanitary measures page url
 *
 * @return string if set, null otherwise
 */
function tkt_sanitary_measures_url()
{
    $eshop_config = TKTApp::get_instance()->get_config('eshop');
    return $eshop_config["url_overrides"]["sanitary_measures_url"][TKT_LANG] ?? null;
}

/**
 * Extract a Youtube video ID from an URL
 * See https://gist.github.com/ghalusa/6c7f3a00fd2383e5ef33
 *
 * @param string: Youtube video url
 *
 * @return string: Video ID
 */
function tkt_yt_video_id($yt_url)
{
    // Here is a sample of the URLs this regex matches: (there can be more content after the given URL that will be ignored)
    // http://youtu.be/dQw4w9WgXcQ
    // http://www.youtube.com/embed/dQw4w9WgXcQ
    // http://www.youtube.com/watch?v=dQw4w9WgXcQ
    // http://www.youtube.com/?v=dQw4w9WgXcQ
    // http://www.youtube.com/v/dQw4w9WgXcQ
    // http://www.youtube.com/e/dQw4w9WgXcQ
    // http://www.youtube.com/user/username#p/u/11/dQw4w9WgXcQ
    // http://www.youtube.com/sandalsResorts#p/c/54B8C800269D7C1B/0/dQw4w9WgXcQ
    // http://www.youtube.com/watch?feature=player_embedded&v=dQw4w9WgXcQ
    // http://www.youtube.com/?feature=player_embedded&v=dQw4w9WgXcQ
    // It also works on the youtube-nocookie.com URL with the same above options.
    // It will also pull the ID from the URL in an embed code (both iframe and object tags)
    preg_match('%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $yt_url, $match);

    return $match[1];
}

/**
 * Helper function to allow to make calls
 * on an object using the __construct() result like
 * $my_obj = tkt_id(new MyObj())->chainable_method();
 */
function tkt_id($obj)
{
    return $obj;
}

if (!function_exists('tkt_h')) {
    /**
     * Sanitize a string for display.
     *
     * Escape HTML tags for a safer display. This function assume UTF-8
     * encoding.
     *
     * @param $string
     *   The unsafe string.
     *
     * @return
     *   a string that can be safely presented to echo or print for output.
     */
    function tkt_h($string)
    {
        return htmlspecialchars($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
    }
}

if (!function_exists('tkt_html')) {
    /**
     * Sanitize a string for display but allows some html tags.
     *
     * Less safe than tkt_h() which strips everything.
     *
     * Note: This function does not modify any attributes on the tags that are
     * allowed, including the style and onmouseover attributes that a mischievous
     * user may abuse when posting text that will be shown to other users.
     *
     * @param $string
     *   The unsafe string.
     *
     * @param $tags_to_keep
     *   Tags to keep in strip tags
     *
     * @return
     *   a string that can be mostly safely presented to echo or print for output.
     */
    function tkt_html($string, $tags_to_keep = '<p><br><b><strong><i><em><a>')
    {
        return strip_tags($string, $tags_to_keep);
    }
}

if (!function_exists('tkt_allowed_tags')) {
    /**
     * Return a list of allowed html tags
     *
     * @return an array
     */
    function tkt_allowed_tags()
    {
        global $allowedposttags;
        $tags = $allowedposttags;

        $tags['form'] = array(
            'action'         => true,
            'accept'         => true,
            'accept-charset' => true,
            'enctype'        => true,
            'method'         => true,
            'name'           => true,
            'target'         => true,
        );
        $tags['script'] = ['type' => true];

        return $tags;
    }
}

function tkt_get_ages()
{
    $array = [tkt_t("Pas de réponse"), "< 5"];
    for ($i=5 ; $i<=80 ; $i++) {
           $array[] = $i;
    }
    $array[] = "> 80";
    return $array;
}

function tkt_get_genders()
{
    return ['n/c' => tkt_t("Pas de réponse"), 'f' => tkt_t("Féminin"), 'm' => tkt_t("Masculin"), 'o' => tkt_t("Autre")];
}

function tkt_get_titles()
{
    return ['n/c' => tkt_t("Pas de réponse"), 'mrs' => tkt_t("Madame"), 'miss' => tkt_t("Mademoiselle"), 'mr' => tkt_t("Monsieur"), 'dr' => ("Docteur")];
}


function tkt_get_countries()
{
    return [
        ['en' => 'Unknown','fr' => 'Inconnu','de' => 'Unknown', 'it' => 'Sconosciuto'],['en' => 'Afghanistan','fr' => 'Afghanistan','de' => 'Afghanistan', 'it' => 'Afghanistan'],['en' => 'Albania','fr' => 'Albanie','de' => 'Albanien', 'it' => 'Albania'],['en' => 'Algeria','fr' => 'Algérie','de' => 'Algerien', 'it' => 'Algeria'],['en' => 'American Samoa','fr' => 'Samoa Américaines','de' => 'Amerikanisch-Samoa', 'it' => 'Samoa americane'],['en' => 'Andorra','fr' => 'Andorre','de' => 'Andorra', 'it' => 'Andorra'],['en' => 'Angola','fr' => 'Angola','de' => 'Angola', 'it' => 'Angola'],['en' => 'Anguilla','fr' => 'Anguilla','de' => 'Anguilla', 'it' => 'Anguilla'],['en' => 'Antarctica','fr' => 'Antarctique','de' => 'Antarktis', 'it' => 'Antartide'],['en' => 'Antigua and Barbuda','fr' => 'Antigua-et-barbuda','de' => 'Antigua and Barbuda', 'it' => 'Antigua e Barbuda'],['en' => 'Argentina','fr' => 'Argentine','de' => 'Argentinien', 'it' => 'Argentina'],['en' => 'Armenia','fr' => 'Arménie','de' => 'Armenien', 'it' => 'Armenia'],['en' => 'Aruba','fr' => 'Aruba','de' => 'Aruba', 'it' => 'Aruba'],['en' => 'Australia','fr' => 'Australie','de' => 'Australien', 'it' => 'Australia'],['en' => 'Austria','fr' => 'Autriche','de' => 'Österreich', 'it' => 'Austria'],['en' => 'Azerbaijan','fr' => 'AzerbaÏdjan','de' => 'Azerbaijan', 'it' => 'Azerbaigian'],['en' => 'Bahamas','fr' => 'Bahamas','de' => 'Bahamas', 'it' => 'Bahamas'],['en' => 'Bahrain','fr' => 'BahreÏn','de' => 'Bahrain', 'it' => 'Bahrein'],['en' => 'Bangladesh','fr' => 'Bangladesh','de' => 'Bangladesch', 'it' => 'Bangladesh'],['en' => 'Barbados','fr' => 'Barbade','de' => 'Barbados', 'it' => 'Barbados'],['en' => 'Belarus','fr' => 'Bélarus','de' => 'Belarus', 'it' => 'Bielorussia'],['en' => 'Belgium','fr' => 'Belgique','de' => 'Belgien', 'it' => 'Belgio'],['en' => 'Belize','fr' => 'Belize','de' => 'Belize', 'it' => 'Belize'],['en' => 'Benin','fr' => 'Bénin','de' => 'Benin', 'it' => 'Benin'],['en' => 'Bermuda','fr' => 'Bermudes','de' => 'Bermuda', 'it' => 'Bermuda'],['en' => 'Bhutan','fr' => 'Bhoutan','de' => 'Bhutan', 'it' => 'Bhutan'],['en' => 'Bolivia','fr' => 'Bolivie, L\'État Plurinational De','de' => 'Bolivien'],['en' => 'Bosnia and Herzegovina','fr' => 'Bosnie-herzégovine','de' => 'Bosnien/Herzegowina', 'it' => 'Bosnia ed Erzegovina'],['en' => 'Botswana','fr' => 'Botswana','de' => 'Botswana', 'it' => 'Botswana'],['en' => 'Bouvet Island','fr' => 'Bouvet, Île','de' => 'Bouvetinsel', 'it' => 'Bouvet, Isola'],['en' => 'Brazil','fr' => 'Brésil','de' => 'Brasilien', 'it' => 'Brasile'],['en' => 'British Indian Ocean Territory','fr' => 'Océan Indien, Territoire Britannique De L\'','de' => 'British Indian Ocean Territor'],['en' => 'Brunei Darussalam','fr' => 'Brunéi Darussalam','de' => 'Brunei Darussalam', 'it' => 'Brunei Darussalam'],['en' => 'Bulgaria','fr' => 'Bulgarie','de' => 'Bulgarien', 'it' => 'Bulgaria'],['en' => 'Burkina Faso','fr' => 'Burkina Faso','de' => 'Burkina Faso', 'it' => 'Burkina Faso'],['en' => 'Burundi','fr' => 'Burundi','de' => 'Burundi', 'it' => 'Burundi'],['en' => 'Cambodia','fr' => 'Cambodge','de' => 'Cambodia', 'it' => 'Cambogia'],['en' => 'Cameroon','fr' => 'Cameroun','de' => 'Cameroon, United Republic of', 'it' => 'Camerun'],['en' => 'Canada','fr' => 'Canada','de' => 'Kanada', 'it' => 'Canada'],['en' => 'Cape Verde','fr' => 'Cap-vert','de' => 'Cape Verde', 'it' => 'Capo Verde'],['en' => 'Cayman Islands','fr' => 'CaÏmanes, Îles','de' => 'Cayman Islands', 'it' => 'Isole Cayman'],['en' => 'Central African Republic','fr' => 'Centrafricaine, République','de' => 'Central African Republic', 'it' => 'Repubblica Centrafricana'],['en' => 'Chad','fr' => 'Tchad','de' => 'Chad', 'it' => 'Chad'],['en' => 'Chile','fr' => 'Chili','de' => 'Chile', 'it' => 'Chile'],['en' => 'China','fr' => 'Chine','de' => 'China', 'it' => 'Cina'],['en' => 'Christmas Island','fr' => 'Christmas, Île','de' => 'Christmas Island', 'it' => 'Natale, Isola'],['en' => 'Cocos (Keeling) Islands','fr' => 'Cocos (keeling), Îles','de' => 'Cocos (Keeling) Islands', 'it' => 'Cocos (keeling), Isole'],['en' => 'Colombia','fr' => 'Colombie','de' => 'Kolumbien', 'it' => 'Colombia'],['en' => 'Comoros','fr' => 'Comores','de' => 'Comoros', 'it' => 'Comore'],['en' => 'Congo','fr' => 'Congo','de' => 'Kongo', 'it' => 'Congo'],['en' => 'Congo, the Democratic Republic of the','fr' => 'Congo, La République Démocratique Du','de' => 'Congo, the Democratic Republic of the', 'it' => 'Congo, Repubblica Democratica del'],['en' => 'Cook Islands','fr' => 'Cook, Îles','de' => 'Cook Islands', 'it' => 'Isole Cook'],['en' => 'Costa Rica','fr' => 'Costa Rica','de' => 'Costa Rica', 'it' => 'Costarica'],['en' => 'Cote D\'Ivoire','fr' => 'Côte D\'ivoire','de' => 'Elfenbeinküste'],['en' => 'Croatia','fr' => 'Croatie','de' => 'Kroatien', 'it' => 'Croazia'],['en' => 'Cuba','fr' => 'Cuba','de' => 'Kuba', 'it' => 'Cuba'],['en' => 'Cyprus','fr' => 'Chypre','de' => 'Zypern', 'it' => 'Cipro'],['en' => 'Czech Republic','fr' => 'Tchèque, République','de' => 'Tschechische Republik', 'it' => 'Repubblica Ceca, Repubblica'],['en' => 'Denmark','fr' => 'Danemark','de' => 'Dänemark', 'it' => 'Danimarca'],['en' => 'Djibouti','fr' => 'Djibouti','de' => 'Dschibuti', 'it' => 'Gibuti'],['en' => 'Dominica','fr' => 'Dominique','de' => 'Dominica', 'it' => 'Dominica'],['en' => 'Dominican Republic','fr' => 'Dominicaine, République','de' => 'Dominikanische Republik', 'it' => 'Repubblica Dominicana'],['en' => 'Ecuador','fr' => 'équateur','de' => 'Ecuador', 'it' => 'Ecuador'],['en' => 'Egypt','fr' => 'Égypte','de' => 'Ägypten', 'it' => 'Egitto'],['en' => 'El Salvador','fr' => 'El Salvador','de' => 'El Salvador', 'it' => 'El Salvador'],['en' => 'Equatorial Guinea','fr' => 'Guinée équatoriale','de' => 'Equatorial Guinea', 'it' => 'Guinea Equatoriale'],['en' => 'Eritrea','fr' => 'Érythrée','de' => 'Eritrea', 'it' => 'Eritrea'],['en' => 'Estonia','fr' => 'Estonie','de' => 'Estland', 'it' => 'Estonia'],['en' => 'Ethiopia','fr' => 'Éthiopie','de' => 'Äthiopien', 'it' => 'Etiopia'],['en' => 'Falkland Islands (Malvinas)','fr' => 'Falkland, Îles (malvinas)','de' => 'Falkland Islands (Malvinas)', 'it' => 'Isole Falkland (Malvine)'],['en' => 'Faroe Islands','fr' => 'Féroé, Îles','de' => 'Faroe Islands', 'it' => 'Isole Faroe'],['en' => 'Fiji','fr' => 'Fidji','de' => 'Fiji', 'it' => 'Figi'],['en' => 'Finland','fr' => 'Finlande','de' => 'Finnland', 'it' => 'Finlandia'],['en' => 'France','fr' => 'France','de' => 'Frankreich', 'it' => 'Francia'],['en' => 'French Guiana','fr' => 'Guyane FranÇaise','de' => 'Französisch-Guyana', 'it' => 'Guiana francese'],['en' => 'French Polynesia','fr' => 'Polynésie FranÇaise','de' => 'Französisch-Polynesien', 'it' => 'Polinesia francese'],['en' => 'French Southern Territories','fr' => 'Terres Australes FranÇaises','de' => 'French Southern Territories', 'it' => 'Terre meridionali francesi'],['en' => 'Gabon','fr' => 'Gabon','de' => 'Gabun', 'it' => 'Gabon'],['en' => 'Gambia','fr' => 'Gambie','de' => 'Gambia', 'it' => 'Gambia'],['en' => 'Georgia','fr' => 'Géorgie','de' => 'Georgien', 'it' => 'Georgia'],['en' => 'Germany','fr' => 'Allemagne','de' => 'Deutschland', 'it' => 'Germania'],['en' => 'Ghana','fr' => 'Ghana','de' => 'Ghana', 'it' => 'Ghana'],['en' => 'Gibraltar','fr' => 'Gibraltar','de' => 'Gibraltar', 'it' => 'Gibilterra'],['en' => 'Greece','fr' => 'Grèce','de' => 'Griechenland', 'it' => 'Grecia'],['en' => 'Greenland','fr' => 'Groenland','de' => 'Grönland', 'it' => 'Groenlandia'],['en' => 'Grenada','fr' => 'Grenade','de' => 'Grenada', 'it' => 'Grenada'],['en' => 'Guadeloupe','fr' => 'Guadeloupe','de' => 'Guadeloupe', 'it' => 'Guadalupa'],['en' => 'Guam','fr' => 'Guam','de' => 'Guam', 'it' => 'Guam'],['en' => 'Guatemala','fr' => 'Guatemala','de' => 'Guatemala', 'it' => 'Guatemala'],['en' => 'Guinea','fr' => 'Guinée','de' => 'Guinea', 'it' => 'Guinea'],['en' => 'Guinea-Bissau','fr' => 'Guinée-bissau','de' => 'Guinea-Bissau', 'it' => 'Guinea-Bissau'],['en' => 'Guyana','fr' => 'Guyana','de' => 'Guyana', 'it' => 'Guyana'],['en' => 'Haiti','fr' => 'HaÏti','de' => 'Haiti', 'it' => 'Haiti'],['en' => 'Heard Island and Mcdonald Islands','fr' => 'Heard, Île Et Mcdonald, Îles','de' => 'Heard and MacDonald Islands', 'it' => 'Sentito, Isola e McDonald, Isole'],['en' => 'Holy See (Vatican City State)','fr' => 'Saint-siège (État De La Cité Du Vatican)','de' => 'Vatikanstadt', 'it' => 'Santa Sede (Stato della Città del Vaticano)'],['en' => 'Honduras','fr' => 'Honduras','de' => 'Honduras', 'it' => 'Honduras'],['en' => 'Hong Kong','fr' => 'Hong-kong','de' => 'Hong Kong', 'it' => 'Hong Kong'],['en' => 'Hungary','fr' => 'Hongrie','de' => 'Ungarn', 'it' => 'Ungheria'],['en' => 'Iceland','fr' => 'Islande','de' => 'Island', 'it' => 'Islanda'],['en' => 'India','fr' => 'Inde','de' => 'Indien', 'it' => 'India'],['en' => 'Indonesia','fr' => 'Indonésie','de' => 'Indonesien', 'it' => 'Indonesia'],['en' => 'Iran, Islamic Republic of','fr' => 'Iran, République Islamique D\'','de' => 'Iran (Islamic Republic of)'],['en' => 'Iraq','fr' => 'Irak','de' => 'Irak', 'it' => 'Iraq'],['en' => 'Ireland','fr' => 'Irlande','de' => 'Irland', 'it' => 'Irlanda'],['en' => 'Israel','fr' => 'Israël','de' => 'Israel', 'it' => 'Israele'],['en' => 'Italy','fr' => 'Italie','de' => 'Italien', 'it' => 'Italia'],['en' => 'Jamaica','fr' => 'JamaÏque','de' => 'Jamaica', 'it' => 'Giamaica'],['en' => 'Japan','fr' => 'Japon','de' => 'Japan', 'it' => 'Giappone'],['en' => 'Jordan','fr' => 'Jordanie','de' => 'Jordanien', 'it' => 'Giordania'],['en' => 'Kazakhstan','fr' => 'Kazakhstan','de' => 'Kazakhstan', 'it' => 'Kazakistan'],['en' => 'Kenya','fr' => 'Kenya','de' => 'Kenia', 'it' => 'Kenia'],['en' => 'Kiribati','fr' => 'Kiribati','de' => 'Kiribati', 'it' => 'Kiribati'],['en' => 'Korea, Democratic People\'s Republic of','fr' => 'Corée, République Populaire Démocratique De','de' => 'Korea, Democratic People s Re'],['en' => 'Korea, Republic of','fr' => 'Corée, République De','de' => 'Korea, Republic of', 'it' => 'Corea, Repubblica di'],['en' => 'Kuwait','fr' => 'KoweÏt','de' => 'Kuwait', 'it' => 'Kuwait'],['en' => 'Kyrgyzstan','fr' => 'Kirghizistan','de' => 'Kyrgystan', 'it' => 'Kirghizistan'],['en' => 'Lao People\'s Democratic Republic','fr' => 'Lao, République Démocratique Populaire','de' => 'Lao People s Democratic Repub'],['en' => 'Latvia','fr' => 'Lettonie','de' => 'Lettland', 'it' => 'Lettonia'],['en' => 'Lebanon','fr' => 'Liban','de' => 'Lebanon', 'it' => 'Libano'],['en' => 'Lesotho','fr' => 'Lesotho','de' => 'Lesotho', 'it' => 'Lesoto'],['en' => 'Liberia','fr' => 'Libéria','de' => 'Liberia', 'it' => 'Liberia'],['en' => 'Libyan Arab Jamahiriya','fr' => 'Libyenne, Jamahiriya Arabe','de' => 'Libyan Arab Jamahiriya', 'it' => 'Libia, Giamahiriya araba'],['en' => 'Liechtenstein','fr' => 'Liechtenstein','de' => 'Liechtenstein', 'it' => 'Liechtenstein'],['en' => 'Lithuania','fr' => 'Lituanie','de' => 'Litauen', 'it' => 'Lituania'],['en' => 'Luxembourg','fr' => 'Luxembourg','de' => 'Luxemburg', 'it' => 'Lussemburgo'],['en' => 'Macao','fr' => 'Macao','de' => 'Macau', 'it' => 'Macao'],['en' => 'Macedonia, the Former Yugoslav Republic of','fr' => 'Macédoine, L\'ex-république Yougoslave De','de' => 'Makedonien'],['en' => 'Madagascar','fr' => 'Madagascar','de' => 'Madagascar', 'it' => 'Madagascar'],['en' => 'Malawi','fr' => 'Malawi','de' => 'Malawi', 'it' => 'Malawi'],['en' => 'Malaysia','fr' => 'Malaisie','de' => 'Malaysia', 'it' => 'Malaysia'],['en' => 'Maldives','fr' => 'Maldives','de' => 'Maldives', 'it' => 'Maldive'],['en' => 'Mali','fr' => 'Mali','de' => 'Mali', 'it' => 'Mali'],['en' => 'Malta','fr' => 'Malte','de' => 'Malta', 'it' => 'Malta'],['en' => 'Marshall Islands','fr' => 'Marshall, Îles','de' => 'Marshall Islands', 'it' => 'Isole Marshall'],['en' => 'Martinique','fr' => 'Martinique','de' => 'Martinique', 'it' => 'Martinica'],['en' => 'Mauritania','fr' => 'Mauritanie','de' => 'Mauritania', 'it' => 'La Mauritania'],['en' => 'Mauritius','fr' => 'Maurice','de' => 'Mauritius', 'it' => 'Maurizio'],['en' => 'Mayotte','fr' => 'Mayotte','de' => 'Mayotte', 'it' => 'Mayotte'],['en' => 'Mexico','fr' => 'Mexique','de' => 'Mexico', 'it' => 'Messico'],['en' => 'Micronesia, Federated States of','fr' => 'Micronésie, États Fédérés De','de' => 'Micronesia', 'it' => 'Micronesia, Stati Federati di'],['en' => 'Moldova, Republic of','fr' => 'Moldavie, République De','de' => 'Moldawien, Republik', 'it' => 'Moldavia, Repubblica di'],['en' => 'Monaco','fr' => 'Monaco','de' => 'Monaco', 'it' => 'Monaco'],['en' => 'Mongolia','fr' => 'Mongolie','de' => 'Mongolei', 'it' => 'Mongolia'],['en' => 'Montserrat','fr' => 'Montserrat','de' => 'Montserrat', 'it' => 'Montserrat'],['en' => 'Morocco','fr' => 'Maroc','de' => 'Marokko', 'it' => 'Marocco'],['en' => 'Mozambique','fr' => 'Mozambique','de' => 'Mozambique', 'it' => 'Mozambico'],['en' => 'Myanmar','fr' => 'Myanmar','de' => 'Myanmar', 'it' => 'Myanmar'],['en' => 'Namibia','fr' => 'Namibie','de' => 'Namibia', 'it' => 'Namibia'],['en' => 'Nauru','fr' => 'Nauru','de' => 'Nauru', 'it' => 'Nauru'],['en' => 'Nepal','fr' => 'Népal','de' => 'Nepal', 'it' => 'Nepal'],['en' => 'Netherlands','fr' => 'Pays-bas','de' => 'Niederlande', 'it' => 'I Paesi Bassi'],['en' => 'Netherlands Antilles','fr' => 'Antilles Néerlandaises','de' => 'Netherlands Antilles', 'it' => 'Antille olandesi'],['en' => 'New Caledonia','fr' => 'Nouvelle-calédonie','de' => 'New Caledonia', 'it' => 'Nuova Caledonia'],['en' => 'New Zealand','fr' => 'Nouvelle-zélande','de' => 'Neuseeland', 'it' => 'Nuova Zelanda'],['en' => 'Nicaragua','fr' => 'Nicaragua','de' => 'Nicaragua', 'it' => 'Nicaragua'],['en' => 'Niger','fr' => 'Niger','de' => 'Niger', 'it' => 'Niger'],['en' => 'Nigeria','fr' => 'Nigéria','de' => 'Nigeria', 'it' => 'Nigeria'],['en' => 'Niue','fr' => 'Niué','de' => 'Niue', 'it' => 'Niue'],['en' => 'Norfolk Island','fr' => 'Norfolk, Île','de' => 'Norfolk Island', 'it' => 'Norfolk, Isola'],['en' => 'Northern Mariana Islands','fr' => 'Mariannes Du Nord, Îles','de' => 'Northern Mariana Islands', 'it' => 'Isole Marianne Settentrionali'],['en' => 'Norway','fr' => 'Norvège','de' => 'Norwegen', 'it' => 'Norvegia'],['en' => 'Oman','fr' => 'Oman','de' => 'Oman', 'it' => 'Oman'],['en' => 'Pakistan','fr' => 'Pakistan','de' => 'Pakistan', 'it' => 'Pakistan'],['en' => 'Palau','fr' => 'Palaos','de' => 'Palau', 'it' => 'Palau'],['en' => 'Palestinian Territory, Occupied','fr' => 'Palestinien Occupé, Territoire','de' => 'Palestinian Territory, Occupied', 'it' => 'Territori palestinesi occupati'],['en' => 'Panama','fr' => 'Panama','de' => 'Panama', 'it' => 'Panama'],['en' => 'Papua New Guinea','fr' => 'Papouasie-nouvelle-guinée','de' => 'Papua New Guinea', 'it' => 'Papua Nuova Guinea'],['en' => 'Paraguay','fr' => 'Paraguay','de' => 'Paraguay', 'it' => 'Paraguay'],['en' => 'Peru','fr' => 'Pérou','de' => 'Peru', 'it' => 'Perù'],['en' => 'Philippines','fr' => 'Philippines','de' => 'Philippines', 'it' => 'Filippine'],['en' => 'Pitcairn','fr' => 'Pitcairn','de' => 'Pitcairn', 'it' => 'Pitcairn'],['en' => 'Poland','fr' => 'Pologne','de' => 'Polen', 'it' => 'Polonia'],['en' => 'Portugal','fr' => 'Portugal','de' => 'Portugal', 'it' => 'Portogallo'],['en' => 'Puerto Rico','fr' => 'Porto Rico','de' => 'Puerto Rico', 'it' => 'Porto Rico'],['en' => 'Qatar','fr' => 'Qatar','de' => 'Qatar', 'it' => 'Qatar'],['en' => 'Reunion','fr' => 'Réunion','de' => 'Reunion', 'it' => 'Riunione'],['en' => 'Romania','fr' => 'Roumanie','de' => 'Rumänien', 'it' => 'Romania'],['en' => 'Russian Federation','fr' => 'Russie, Fédération De','de' => 'Rußland', 'it' => 'Russia, Federazione'],['en' => 'Rwanda','fr' => 'Rwanda','de' => 'Rwanda', 'it' => 'Ruanda'],['en' => 'Saint Helena','fr' => 'Sainte-hélène, Ascension Et Tristan Da Cunha','de' => 'Saint Helena', 'it' => 'Sant\'Elena, Ascensione e Tristan Da Cunha'],['en' => 'Saint Kitts and Nevis','fr' => 'Saint-kitts-et-nevis','de' => 'Saint Kitts and Nevis', 'it' => 'Saint Kitts e Nevis'],['en' => 'Saint Lucia','fr' => 'Sainte-lucie','de' => 'Saint Lucia', 'it' => 'Santa Lucia'],['en' => 'Saint Pierre and Miquelon','fr' => 'Saint-pierre-et-miquelon','de' => 'Saint Pierre and Miquelon', 'it' => 'Saint Pierre e Miquelon'],['en' => 'Saint Vincent and the Grenadines','fr' => 'Saint-vincent-et-les Grenadines','de' => 'Saint Vincent and the Grenadi', 'it' => 'Saint Vincent e Grenadine'],['en' => 'Samoa','fr' => 'Samoa','de' => 'Western Samoa', 'it' => 'Samoa'],['en' => 'San Marino','fr' => 'Saint-marin','de' => 'San Marino', 'it' => 'San Marino'],['en' => 'Sao Tome and Principe','fr' => 'Sao Tomé-et-principe','de' => 'Sao Tome and Principe', 'it' => 'Sao Tomé e Principe'],['en' => 'Saudi Arabia','fr' => 'Arabie Saoudite','de' => 'Saudi Arabia', 'it' => 'Arabia Saudita'],['en' => 'Senegal','fr' => 'Sénégal','de' => 'Senegal', 'it' => 'Senegal'],['en' => 'Serbia and Montenegro','fr' => 'Serbie et Monténégro','de' => 'Serbia and Montenegro', 'it' => 'Serbia e Montenegro'],['en' => 'Seychelles','fr' => 'Seychelles','de' => 'Seychelles', 'it' => 'Seychelles'],['en' => 'Sierra Leone','fr' => 'Sierra Leone','de' => 'Sierra Leone', 'it' => 'Sierra Leone'],['en' => 'Singapore','fr' => 'Singapour','de' => 'Singapore', 'it' => 'Singapore'],['en' => 'Slovakia','fr' => 'Slovaquie','de' => 'Slovakei', 'it' => 'Slovacchia'],['en' => 'Slovenia','fr' => 'Slovénie','de' => 'Slowenien', 'it' => 'Slovenia'],['en' => 'Solomon Islands','fr' => 'Salomon, Îles','de' => 'Solomon Islands', 'it' => 'Isole Salomone'],['en' => 'Somalia','fr' => 'Somalie','de' => 'Somalia', 'it' => 'Somalia'],['en' => 'South Africa','fr' => 'Afrique Du Sud','de' => 'Südafrika', 'it' => 'Sudafrica'],['en' => 'South Georgia and the South Sandwich Islands','fr' => 'Géorgie Du Sud Et Les Îles Sandwich Du Sud','de' => 'South Georgia and the South Sandwich Islands', 'it' => 'Georgia del Sud e Isole Sandwich Meridionali'],['en' => 'Spain','fr' => 'Espagne','de' => 'Spanien', 'it' => 'Spagna'],['en' => 'Sri Lanka','fr' => 'Sri Lanka','de' => 'Sri Lanka', 'it' => 'Sri Lanka'],['en' => 'Sudan','fr' => 'Soudan','de' => 'Sudan', 'it' => 'Sudan'],['en' => 'Suriname','fr' => 'Suriname','de' => 'Surinam', 'it' => 'Suriname'],['en' => 'Svalbard and Jan Mayen','fr' => 'Svalbard Et Île Jan Mayen','de' => 'Svalbard and Jan Mayen Island', 'it' => 'Svalbard e Jan Mayen'],['en' => 'Swaziland','fr' => 'Swaziland','de' => 'Swaziland', 'it' => 'Swaziland'],['en' => 'Sweden','fr' => 'Suède','de' => 'Schweden', 'it' => 'Svezia'],['en' => 'Switzerland','fr' => 'Suisse','de' => 'Schweiz', 'it' => 'Svizzera'],['en' => 'Syrian Arab Republic','fr' => 'Syrienne, République Arabe','de' => 'Syrian Arab Republic', 'it' => 'Siria, Repubblica araba'],['en' => 'Taiwan, Province of China','fr' => 'TaÏwan, Province De Chine','de' => 'Taiwan, Province of China', 'it' => 'Taiwan, provincia della Cina'],['en' => 'Tajikistan','fr' => 'Tadjikistan','de' => 'Tajikistan', 'it' => 'Tagikistan'],['en' => 'Tanzania, United Republic of','fr' => 'Tanzanie, République-unie De','de' => 'Tanzania, United Republic of', 'it' => 'Tanzania, Repubblica Unita di'],['en' => 'Thailand','fr' => 'ThaÏlande','de' => 'Thailand', 'it' => 'Tailandia'],['en' => 'Timor-Leste','fr' => 'Timor-leste','de' => 'Timor-Leste', 'it' => 'Timor Est'],['en' => 'Togo','fr' => 'Togo','de' => 'Togo', 'it' => 'Togo'],['en' => 'Tokelau','fr' => 'Tokelau','de' => 'Tokelau', 'it' => 'Tokelau'],['en' => 'Tonga','fr' => 'Tonga','de' => 'Tonga', 'it' => 'Tonga'],['en' => 'Trinidad and Tobago','fr' => 'Trinité-et-tobago','de' => 'Trinidad and Tobago', 'it' => 'Trinidad e Tobago'],['en' => 'Tunisia','fr' => 'Tunisie','de' => 'Tunesien', 'it' => 'Tunisia'],['en' => 'Turkey','fr' => 'Turquie','de' => 'Türkei', 'it' => 'Turchia'],['en' => 'Turkmenistan','fr' => 'Turkménistan','de' => 'Turkemistan', 'it' => 'Turkmenistan'],['en' => 'Turks and Caicos Islands','fr' => 'Turks Et CaÏques, Îles','de' => 'Turks and Caicos Islands', 'it' => 'Isole Turks e Caicos'],['en' => 'Tuvalu','fr' => 'Tuvalu','de' => 'Tuvalu', 'it' => 'Tuvalu'],['en' => 'Uganda','fr' => 'Ouganda','de' => 'Uganda', 'it' => 'Uganda'],['en' => 'Ukraine','fr' => 'Ukraine','de' => 'Ukraine', 'it' => 'Ucraina'],['en' => 'United Arab Emirates','fr' => 'émirats Arabes Unis','de' => 'United Arab Emirates', 'it' => 'Emirati Arabi Uniti'],['en' => 'United Kingdom','fr' => 'Royaume-uni','de' => 'Vereinigtes Königreich', 'it' => 'Regno Unito'],['en' => 'United States','fr' => 'États-unis','de' => 'Vereinigte Staaten von Amerik', 'it' => 'STATI UNITI'],['en' => 'United States Minor Outlying Islands','fr' => 'Îles Mineures éloignées Des États-unis','de' => 'United States Minor Outlying', 'it' => 'Isole minori esterne degli Stati Uniti'],['en' => 'Uruguay','fr' => 'Uruguay','de' => 'Uruguay', 'it' => 'Uruguay'],['en' => 'Uzbekistan','fr' => 'Ouzbékistan','de' => 'Uzbekistan', 'it' => 'Uzbekistan'],['en' => 'Vanuatu','fr' => 'Vanuatu','de' => 'Vanuatu', 'it' => 'Vanuatu'],['en' => 'Venezuela','fr' => 'Venezuela, République Bolivarienne Du','de' => 'Venezuela', 'it' => 'Venezuela, Repubblica Bolivariana di'],['en' => 'Viet Nam','fr' => 'Viêt-Nam','de' => 'Vietnam', 'it' => 'Vietnam'],['en' => 'Virgin Islands, British','fr' => 'Îles Vierges Britanniques','de' => 'Virgin Islands (British)', 'it' => 'Isole Vergini britanniche'],['en' => 'Virgin Islands, U.s.','fr' => 'Îles Vierges Des États-unis','de' => 'Virgin Islands (U.S.)', 'it' => 'Isole Vergini americane'],['en' => 'Wallis and Futuna','fr' => 'Wallis Et Futuna','de' => 'Wallis and Futuna Islands', 'it' => 'Wallis e Futuna'],['en' => 'Western Sahara','fr' => 'Sahara Occidental','de' => 'Western Sahara', 'it' => 'Sahara occidentale'],['en' => 'Yemen','fr' => 'Yémen','de' => 'Yemen, Republic of', 'it' => 'Yemen'],['en' => 'Zambia','fr' => 'Zambie','de' => 'Zambia', 'it' => 'Zambia'],['en' => 'Zimbabwe','fr' => 'Zimbabwe','de' => 'Zimbabwe', 'it' => 'Zimbabwe'],['en' => 'Kosovo','fr' => 'Kosovo','de' => 'Kosovo', 'it' => 'Kosovo'],['en' => 'Serbia','fr' => 'Serbie','de' => 'Serbia', 'it' => 'Serbia'],['en' => 'Zaire','fr' => 'Zaïre','de' => 'Zaire', 'it' => 'Zaire'],['en' => 'Yugoslavia','fr' => 'Yougoslavie','de' => 'Jugoslawien', 'it' => 'Jugoslavia']
    ];
}

/**
 * Pick a localized string from an opaque payload (array or object keyed by locale, e.g. description).
 *
 * @param mixed  $payload
 * @param string $preferred_lang E.g. TKT_LANG
 * @return string
 */
function tkt_opaque_pick_localized_string($payload, $preferred_lang = null)
{
    if ($payload === null) {
        return '';
    }
    $payload = is_array($payload) ? $payload : (array) $payload;
    $preferred_lang = $preferred_lang ?: (defined('TKT_LANG') ? TKT_LANG : 'fr');
    if (isset($payload[$preferred_lang]) && $payload[$preferred_lang] !== '' && $payload[$preferred_lang] !== null) {
        return (string) $payload[$preferred_lang];
    }
    $default_lang = tkt_default_lang();
    if ($default_lang !== $preferred_lang
        && isset($payload[$default_lang])
        && $payload[$default_lang] !== ''
        && $payload[$default_lang] !== null
    ) {
        return (string) $payload[$default_lang];
    }
    return '';
}

/**
 * Normalize a language entry (legacy ISO string or expanded object with iso2 + labels) to uppercase ISO639-1 code.
 *
 * @param mixed $entry
 * @return string Uppercased code or empty string
 */
function tkt_opaque_language_iso2_upper($entry)
{
    if ($entry === null || $entry === '') {
        return '';
    }
    if (is_string($entry)) {
        return strtoupper($entry);
    }
    if (is_array($entry) && isset($entry['iso2'])) {
        return strtoupper((string) $entry['iso2']);
    }
    if (is_object($entry) && isset($entry->iso2)) {
        return strtoupper((string) $entry->iso2);
    }
    return '';
}

/**
 * Whether the normalized language code is a pseudo-code (NO_LANG, …) rather than ISO639-1 (2 letters).
 * Used when deciding « VO » vs showing the localized label (e.g. « Pas de dialogue »).
 *
 * @param string $iso2_upper Output of {@see tkt_opaque_language_iso2_upper()} for one entry.
 */
function tkt_opaque_language_iso_is_extended($iso2_upper)
{
    return $iso2_upper !== '' && strlen($iso2_upper) > 2;
}

/**
 * Compact label for agenda-style audio/ST lines: ISO639-1 codes stay uppercase;
 * longer pseudo-codes (e.g. no_lang / NO_LANG) use the localized label when present.
 *
 * Mirrors logic introduced in program/agenda/day.tpl.php (Fix B7555).
 *
 * @param mixed $entry Legacy ISO string or expanded `{ iso2, fr, en, … }`.
 * @param string|null $preferred_lang Defaults to TKT_LANG.
 * @return string Token without forcing uppercase on localized phrases (caller may uppercase whole CSV).
 */
function tkt_opaque_language_compact_token($entry, $preferred_lang = null)
{
    if ($entry === null || $entry === '') {
        return '';
    }
    $preferred_lang = $preferred_lang ?: (defined('TKT_LANG') ? TKT_LANG : 'fr');
    if (is_string($entry)) {
        return strtoupper($entry);
    }
    $iso2 = '';
    $localized = '';
    if (is_array($entry)) {
        $iso2 = isset($entry['iso2']) ? (string) $entry['iso2'] : '';
        $localized = isset($entry[$preferred_lang]) ? (string) $entry[$preferred_lang] : '';
    } elseif (is_object($entry)) {
        $iso2 = isset($entry->iso2) ? (string) $entry->iso2 : '';
        $localized = isset($entry->$preferred_lang) ? (string) $entry->$preferred_lang : '';
    }
    if ($iso2 !== '' && strlen($iso2) > 2) {
        return ($localized !== '') ? $localized : strtoupper($iso2);
    }
    return strtoupper($iso2);
}

/**
 * Return first language entry: supports legacy string, array of entries, or single object.
 *
 * @param mixed $mixed
 * @return mixed|null
 */
function tkt_opaque_language_first($mixed)
{
    if ($mixed === null || $mixed === '') {
        return null;
    }
    if (is_string($mixed)) {
        return $mixed;
    }
    if (is_array($mixed)) {
        if (array_key_exists('iso2', $mixed)) {
            return $mixed;
        }
        return isset($mixed[0]) ? $mixed[0] : null;
    }
    if (is_object($mixed)) {
        return $mixed;
    }
    return null;
}

/**
 * Normalize subtitles payload to a flat list (legacy string -> single-item list).
 *
 * @param mixed $subs
 * @return array
 */
function tkt_opaque_normalize_subtitles_list($subs)
{
    if ($subs === null || $subs === '') {
        return [];
    }
    if (!is_array($subs)) {
        return [$subs];
    }
    return $subs;
}

/**
 * ISO-3166 alpha-2 codes missing from some reference datasets (e.g. Kosovo).
 *
 * @return array<string, array<string, string>>
 */
function tkt_extra_countries_by_iso()
{
    return [
        'XK' => ['en' => 'Kosovo', 'fr' => 'Kosovo', 'de' => 'Kosovo'],
    ];
}

/**
 * @param mixed $country
 * @return string Uppercase ISO-3166 alpha-2 or empty string.
 */
function tkt_opaque_country_iso2($country)
{
    if ($country === null || $country === '') {
        return '';
    }
    if (is_string($country)) {
        return strlen($country) === 2 ? strtoupper($country) : '';
    }
    if (is_array($country)) {
        if (!empty($country['iso2'])) {
            return strtoupper((string) $country['iso2']);
        }
        if (!empty($country['code'])) {
            return strtoupper((string) $country['code']);
        }
        return '';
    }
    if (is_object($country)) {
        if (!empty($country->iso2)) {
            return strtoupper((string) $country->iso2);
        }
        if (!empty($country->code)) {
            return strtoupper((string) $country->code);
        }
    }
    return '';
}

/**
 * @param mixed  $country
 * @param string $preferred_lang
 * @return string
 */
function tkt_opaque_country_localized_label($country, $preferred_lang)
{
    if (is_array($country) && isset($country[$preferred_lang]) && $country[$preferred_lang] !== '') {
        return (string) $country[$preferred_lang];
    }
    if (is_object($country) && isset($country->$preferred_lang) && $country->$preferred_lang !== '') {
        return (string) $country->$preferred_lang;
    }
    return '';
}

/**
 * @param string $label
 * @param string $iso2
 * @return bool
 */
function tkt_opaque_country_label_is_usable($label, $iso2)
{
    if ($label === '') {
        return false;
    }
    if ($iso2 !== '' && strcasecmp($label, $iso2) === 0) {
        return false;
    }
    return true;
}

/**
 * @param string      $iso2
 * @param string|null $preferred_lang
 * @return string
 */
function tkt_country_name_from_iso2($iso2, $preferred_lang = null)
{
    static $cache = [];

    $iso2 = strtoupper(trim($iso2));
    if ($iso2 === '') {
        return '';
    }

    $preferred_lang = $preferred_lang ?: (defined('TKT_LANG') ? TKT_LANG : 'fr');
    $cache_key = $iso2 . ':' . $preferred_lang;
    if (array_key_exists($cache_key, $cache)) {
        return $cache[$cache_key];
    }

    $extra = tkt_extra_countries_by_iso();
    if (isset($extra[$iso2][$preferred_lang])) {
        $cache[$cache_key] = $extra[$iso2][$preferred_lang];
        return $cache[$cache_key];
    }

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

/**
 * Display label for a country entry (legacy ISO string or expanded object with iso2 + localized labels).
 *
 * @param mixed  $country
 * @param string|null $preferred_lang
 * @return string
 */
function tkt_opaque_country_display($country, $preferred_lang = null)
{
    if ($country === null || $country === '') {
        return '';
    }

    $preferred_lang = $preferred_lang ?: (defined('TKT_LANG') ? TKT_LANG : 'fr');

    if (is_string($country)) {
        if (strlen($country) === 2) {
            return tkt_country_name_from_iso2($country, $preferred_lang);
        }
        return $country;
    }

    $iso2 = tkt_opaque_country_iso2($country);
    $localized = tkt_opaque_country_localized_label($country, $preferred_lang);

    if (tkt_opaque_country_label_is_usable($localized, $iso2)) {
        return $localized;
    }

    if ($iso2 !== '') {
        return tkt_country_name_from_iso2($iso2, $preferred_lang);
    }

    return $localized;
}

/**
 * @param $str
 *   the string to match.
 *
 * @return
 *   true if the given string is a UUIDv4, false otherwise.
 */
function tkt_is_uuidv4($str)
{
    $regexp = '/^[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-4[A-Fa-f0-9]{3}-[ABab89][A-Fa-f0-9]{3}-[A-Fa-f0-9]{12}$/';
    return (preg_match($regexp, $str) ? true : false);
}

if (!function_exists('tkt_invalid_url_path_encode_url')) {
    // https://stackoverflow.com/questions/9831077/how-to-url-encode-only-non-ascii-symbols-of-url-in-php-but-leave-reserved-symbo
    function tkt_invalid_url_path_encode_url($url)
    {
        $path = parse_url($url, PHP_URL_PATH);
        if ($path !== false && strpos($path, '%') !== false) return $url; // avoid double encoding
        else {
            $encoded_path = array_map('rawurlencode', explode('/', $path));
            return str_replace($path, implode('/', $encoded_path), $url);
        }
    }
}

if (!function_exists('tkt_img_proxy_url')) {
    function tkt_img_proxy_url($remote_url, $max_width = null, $max_height = null, $animation = false)
    {
        $proxy_img_host = TKTApp::get_instance()->get_config("integrations.weserv.proxy_img_host");
        if (empty($proxy_img_host)) {
            return $remote_url;
        }

        if (!filter_var($remote_url, FILTER_VALIDATE_URL)) {
            // sometimes we get non RFC 1738 urls, let's be nice and try to fix it
            $remote_url =tkt_invalid_url_path_encode_url($remote_url);
            if (!filter_var($remote_url, FILTER_VALIDATE_URL)) {
                return false;
            }
        }

        // Default output, webp is supported by 98% of users as of 2024
        $output = 'webp';

        $n = $animation ? '-1' : null;

        return sprintf(
            "https://%s/?%s",
            $proxy_img_host,
            http_build_query(['url' => $remote_url, 'w' => $max_width, 'h' => $max_height, 'output' => $output, 'q' => 70, 'fit' => 'outside', 'n' => $n])
        );
    }
}

if (!function_exists('tkt_base64url_encode')) {
    /**
     * base64url variants,
     * stolen from http://us3.php.net/manual/en/function.base64-encode.php#103849
     */
    function tkt_base64url_encode($data)
    {
        return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
    }
}

if (!function_exists('tkt_base64url_decode')) {
    function tkt_base64url_decode($data)
    {
        return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
    }
}

/**
 * Wrap Wordpress __ function
 */
function tkt_t($str) {
    return __($str, 'wpticketack');
}


function tkt_get_event_slug($event, $lang)
{
    $title = $event->localized_title_or_default_or_original($lang);
    // sanitize_title, uses remove_accents that removes accents differently depending on locale
    // e.g. ö is replaced by o usually but by oe if locale is German
    // This makes the slug computed different depending on the wordpress admin locale than the current user's locale
    // Let's fix that by forcing accent removal in a defined way.
    // https://developer.wordpress.org/reference/functions/remove_accents/
    $title = remove_accents($title, /* locale */ 'en_US');
    $slug  = sanitize_title($title).($lang === tkt_default_lang() ? '' : '-'.$lang);

    return $slug;
}

function tkt_get_article_slug($article, $lang)
{
    $title = $article->name($lang);
    $slug  = sanitize_title($title).($lang === tkt_default_lang() ? '' : '-'.$lang);

    return $slug;
}

/**
 * Generate html data attributes based on defined attributes
 *
 * @param TKTEvent $event
 * @param array $attributes
 */
function tkt_event_data_attributes($event, $attributes)
{
    $values = [];
    if (in_array('type', $attributes)) {
        $values[] = 'data-type="'.$event->opaque('type').'"';
    }

    if (in_array('date', $attributes)) {
        $dates = [];
        foreach ($event->screenings() as $s) {
            $dates[] = $s->start_at()->format('Y-m-d');
        }
            $values[] = 'data-date="'.implode(',', $dates).'"';
    }

    if (in_array('tags', $attributes)) {
        $tags = [];
        foreach ($event->opaque('tags', []) as $tag) {
            $tags[] = $tag[TKT_LANG];
        }
        $values[] = 'data-tags="'.implode(',', $tags).'"';
    }

    if (in_array('section', $attributes)) {
        $sections = [];
        foreach ($event->screenings() as $s) {
            foreach ($s->sections() as $section) {
                $sections[] = $section->name(TKT_LANG);
            }
        }
        $values[] = 'data-section="'.implode(',', $sections).'"';
    }

    return implode(' ', $values);
}


/**
 * Generate html data attributes based on defined attributes
 *
 * @param TKTEvent $screening
 * @param array $attributes
 */
function tkt_screening_data_attributes($screening, $attributes)
{
    $values = [];
    if (in_array('type', $attributes)) {
        if (!empty($screening->opaque('type'))) {
            $values[] = 'data-type="'.$screening->opaque('type').'"';
        } else {
            $event = current($screening->movies());
            if ($event) {
                $values[] = 'data-type="'.$event->opaque('type').'"';
            }
        }
    }

    if (in_array('date', $attributes)) {
        $values[] = 'data-date="'.$screening->start_at()->format('Y-m-d').'"';
    }

    if (in_array('hall', $attributes)) {
        $values[] = 'data-hall="'.$screening->place()->name().'"';
    }

    if (in_array('sections', $attributes)) {
        $sections = [];
        foreach ($screening->sections() as $section) {
            $sections[] = $section->name(tkt_default_lang());
        }
        $values[] = 'data-section="'.implode(',', $sections).'"';
    }

    if (in_array('tags', $attributes)) {
        $tags = [];
        foreach ($screening->opaque('tags', []) as $tag) {
            $tags[] = $tag[TKT_LANG];
        }
        $values[] = 'data-tags="'.implode(',', $tags).'"';
    }

    return implode(' ', $values);
}

/**
 * Generate html data attributes based on defined attributes
 *
 * @param TKTPerson $person
 * @param array $attributes
 */
function tkt_person_data_attributes($person, $attributes)
{
    $meta   = get_post_meta($person->ID);
    $values = [];
    $tags   = [];

    if (in_array('name', $attributes)) {
        $values[] = 'data-name="'.$person->post_content.'"';
        $tags[]   = $person->post_content;
    }

    if (in_array('country', $attributes)) {
        $values[] = 'data-country="'.$meta['country'][0].'"';
        $tags[]   = $meta['country'][0];
    }

    if (in_array('company', $attributes)) {
        $values[] = 'data-company="'.$meta['company'][0].'"';
        $tags[]   = $meta['company'][0];
    }

    if (in_array('profession', $attributes)) {
        $values[] = 'data-profession="'.$meta['profession'][0].'"';
        $tags[]   = $meta['profession'][0];
    }

    if (in_array('tags', $attributes)) {
        $values[] = 'data-tags="'.implode(' ', array_unique($tags)).'"';
    }

    return implode(' ', $values);
}

/**
 * Get the configured default lang
 *
 * @return string
 */
function tkt_default_lang()
{
    return TKTApp::get_instance()->get_config('i18n.default_lang', 'fr');
}

/**
 * Get the configured cart/booking reservation duration, in minutes.
 *
 * The engine exposes this as an ISO 8601 duration string (e.g. "PT30M")
 * through the "eshop.booking_expiration_duration" setting.
 *
 * @param int $default: Fallback value in minutes if the setting is missing or invalid
 *
 * @return int
 */
function tkt_booking_expiration_minutes($default = 30)
{
    $duration = TKTApp::get_instance()->get_config('eshop.booking_expiration_duration');
    if (empty($duration) || !is_string($duration)) {
        return $default;
    }

    try {
        $interval = new \DateInterval($duration);
    } catch (\Exception $e) {
        return $default;
    }

    $minutes = ($interval->y * 525600)
        + ($interval->m * 43200)
        + ($interval->d * 1440)
        + ($interval->h * 60)
        + $interval->i;

    return $minutes > 0 ? $minutes : $default;
}

/**
 * Get the configured default lang
 *
 * @return string
 */
function tkt_current_lang()
{
    if (!TKT_WPML_INSTALLED) {
        return tkt_default_lang();
    }

    return ICL_LANGUAGE_CODE;
}

/**
 * Get the translated slug of a post
 *
 * @param int $id: The post id
 * @param string $type: The post type (post, page, tkt-event, ...)
 * @param string $lang: The desired language
 * @param string $default: default value
 *
 * @return string: The slug in the desired language
 */
function tkt_translated_slug_by_id($id, $type, $lang, $default)
{
    if (!TKT_WPML_INSTALLED) {
        return $default;
    }

    // get the post ID in $lang
    $post_id = icl_object_id($id, $type, FALSE, $lang);
    // get the post object
    $post_obj = get_post($post_id);

    return $post_obj->post_name;
}

/**
 * Get the id of a translated post
 *
 * @param int $id: The post id
 * @param string $type: The post type (post, page, tkt-event, ...)
 * @param string $lang: The desired language
 * @param string $default: default value
 *
 * @return int: The id of the post in the desired language
 */
function tkt_translated_id_by_id($id, $type, $lang, $default)
{
    if (!TKT_WPML_INSTALLED) {
        return $default;
    }

    // get the post ID in $lang
    $post_id = icl_object_id($id, $type, FALSE, $lang);

    // get the post object
    $post_obj = get_post($post_id);

    return $post_obj->ID;
}

/**
 * Return a list of overridable scss variables.
 */
function tkt_get_overridable_scss_variables()
{
    return [
        'text_color' => '#000',
        'error_color' => '#ce6060',
        'link_color' => '#007BFF',
        'active_color' => '#1C99E2',
        'btn_bg_color' => '#121212',
        'btn_text_color' => '#FFFFFF',
        'input_bg_color' => '#FFFFFF',
        'input_text_color' => '#000000',
        'section_padding' => '20px',
        'light_section_bg_color' => '#F0F0F0',
        'light_section_text_color' => '#000',
        'dark_section_bg_color' => '#212121',
        'dark_section_text_color' => '#FFF',
        'badge_bg_color' => '#FFF',
        'badge_text_color' => '#000',
        'badge_active_bg_color' => '#1C99E2',
        'badge_active_text_color' => '#FFF',
        'badge_title_bg_color' => '#000',
        'badge_title_text_color' => '#FFF',
        'badge_value_bg_color' => '#333',
        'badge_value_text_color' => '#FFF',
        'border_radius' => '4px',
    ];
}

/**
 * Compile scss override file with the variables
 * provided by `tkt_get_overridable_scss_variables()`.
 */
function tkt_compile_scss_override()
{
    $scss = new Compiler();
    $base_path = plugin_dir_path(TKT_APP).'front/build/';
    $scss->setImportPaths($base_path);
    $scss->setOutputStyle(\ScssPhp\ScssPhp\OutputStyle::COMPRESSED);

    $variables = tkt_get_overridable_scss_variables();
    foreach ($variables as $name => $value) {
        $variables[$name] = ValueConverter::parseValue(TKTApp::get_instance()->get_config('advanced.'.$name, $value));
    }

    $font_path = plugins_url('front/build/fonts', TKT_APP);
    $font_path = wp_make_link_relative($font_path);
    $variables['tkt-icon-font-path'] = ValueConverter::parseValue("'$font_path'");

    $scss->replaceVariables($variables);

    $output_path = TKT_OVERRIDE_DIR.'/tkt_override.css';
    file_put_contents($output_path, $scss->compileString('@import "override.scss";')->getCss());
}


/**
 * Add a flash notice to {prefix}options table until a full page refresh is done
 *
 * @param string $notice our notice message
 * @param string $type This can be "info", "warning", "error" or "success", "warning" as default
 * @param boolean $dismissible set this to true to add is-dismissible functionality to your notice
 * @return void
 */
function tkt_flash_notice($notice = '', $type = 'warning', $dismissible = true)
{
    $notices = get_option('tkt_flash_notices', []);

    foreach ($notices as $existing) {
        if ($existing['notice'] === $notice && $existing['type'] === $type) {
            return;
        }
    }

    array_push($notices, [
        'notice'      => $notice,
        'type'        => $type,
        'dismissible' => $dismissible ? 'is-dismissible' : ''
    ]);

    // Then we update the option with our notices array
    update_option('tkt_flash_notices', $notices);
}

function tkt_ticketidize($str)
{
    return str_replace('TicketID', '<span class="tkt-ticketid_ticket">Ticket</span><span class="tkt-ticketid_id">ID</span>', $str);
}

/**
 * Help text shown next to TicketID login fields.
 */
function tkt_ticketid_help_text(): string
{
    return tkt_ticketidize(BSTranslator::t(
        "Votre TicketID est composé d'un identifiant de 6 chiffres suivi d'un code alphanumérique et se trouve sur votre billet, abonnement ou accréditation."
    ));
}

function tkt_original($title)
{
    // original is mandatory, no need to ?? null here
    return ((object) $title)->original;
}

function tkt_localized_or_default($property, $lang)
{
    $property = (array) $property;
    $default_lang = tkt_default_lang();

    if (!empty($property[$lang])) {
        return $property[$lang];
    }
    if ($default_lang !== $lang && !empty($property[$default_lang])) {
        return $property[$default_lang];
    }

    return null;
}

function tkt_localized_or_original($title, $lang)
{
    $localized = ((object) $title)->{$lang} ?? null;
    $original  = tkt_original($title);
    return ($localized ?? $original);
}

function tkt_localized_or_default_or_original($title, $lang)
{
    $localized = ((object) $title)->{$lang} ?? null;
    $default   = ((object) $title)->{tkt_default_lang()} ?? null;

    $original  = tkt_original($title);
    return ($localized ?? $default ?? $original);
}


function tkt_original_if_different_from_localized($title, $lang)
{
    $localized = ((object) $title)->{$lang} ?? null;
    $original  = tkt_original($title);
    return ($original != $localized) ? $original : null;
}

