<?php

namespace FluentBooking\App\Services;

use FluentBooking\App\App;
use FluentBooking\App\Models\Booking;
use FluentBooking\App\Models\Calendar;
use FluentBooking\App\Models\CalendarSlot;
use FluentBooking\App\Models\Meta;
use FluentBooking\App\Models\BookingMeta;
use FluentBooking\Framework\Support\Arr;

class Helper
{
    public static $reserved = [
        '0',
        'about',
        'access',
        'account',
        'accounts',
        'activate',
        'activities',
        'activity',
        'ad',
        'add',
        'address',
        'adm',
        'admin',
        'administration',
        'administrator',
        'ads',
        'adult',
        'advertising',
        'affiliate',
        'affiliates',
        'ajax',
        'all',
        'alpha',
        'analysis',
        'analytics',
        'android',
        'anon',
        'anonymous',
        'api',
        'app',
        'apps',
        'archive',
        'archives',
        'article',
        'asct',
        'asset',
        'atom',
        'auth',
        'authentication',
        'avatar',
        'backup',
        'balancer-manager',
        'banner',
        'banners',
        'beta',
        'billing',
        'bin',
        'blog',
        'blogs',
        'board',
        'book',
        'bookmark',
        'bot',
        'bots',
        'bug',
        'business',
        'cache',
        'cadastro',
        'calendar',
        'call',
        'campaign',
        'cancel',
        'captcha',
        'career',
        'careers',
        'cart',
        'categories',
        'category',
        'cgi',
        'cgi-bin',
        'changelog',
        'chat',
        'check',
        'checking',
        'checkout',
        'client',
        'cliente',
        'clients',
        'code',
        'codereview',
        'comercial',
        'comment',
        'comments',
        'communities',
        'community',
        'company',
        'compare',
        'compras',
        'config',
        'configuration',
        'connect',
        'contact',
        'contact-us',
        'contact_us',
        'contactus',
        'contest',
        'contribute',
        'corp',
        'create',
        'css',
        'dashboard',
        'data',
        'db',
        'default',
        'delete',
        'demo',
        'design',
        'designer',
        'destroy',
        'dev',
        'devel',
        'developer',
        'developers',
        'diagram',
        'diary',
        'dict',
        'dictionary',
        'die',
        'dir',
        'direct_messages',
        'directory',
        'dist',
        'doc',
        'docs',
        'documentation',
        'domain',
        'download',
        'downloads',
        'ecommerce',
        'edit',
        'editor',
        'edu',
        'education',
        'email',
        'employment',
        'empty',
        'end',
        'enterprise',
        'entries',
        'entry',
        'error',
        'errors',
        'eval',
        'event',
        'exit',
        'explore',
        'facebook',
        'faq',
        'favorite',
        'favorites',
        'feature',
        'features',
        'feed',
        'feedback',
        'feeds',
        'file',
        'files',
        'first',
        'flash',
        'fleet',
        'fleets',
        'flog',
        'follow',
        'followers',
        'following',
        'forgot',
        'form',
        'forum',
        'forums',
        'founder',
        'free',
        'friend',
        'friends',
        'ftp',
        'gadget',
        'gadgets',
        'game',
        'games',
        'get',
        'ghost',
        'gift',
        'gifts',
        'gist',
        'github',
        'graph',
        'group',
        'groups',
        'guest',
        'guests',
        'help',
        'home',
        'homepage',
        'host',
        'hosting',
        'hostmaster',
        'hostname',
        'howto',
        'hpg',
        'html',
        'http',
        'httpd',
        'https',
        'i',
        'iamges',
        'icon',
        'icons',
        'id',
        'idea',
        'ideas',
        'image',
        'images',
        'imap',
        'img',
        'index',
        'indice',
        'info',
        'information',
        'inquiry',
        'instagram',
        'intranet',
        'invitations',
        'invite',
        'ipad',
        'iphone',
        'irc',
        'is',
        'issue',
        'issues',
        'it',
        'item',
        'items',
        'java',
        'javascript',
        'job',
        'jobs',
        'join',
        'js',
        'json',
        'jump',
        'knowledgebase',
        'language',
        'languages',
        'last',
        'ldap-status',
        'legal',
        'license',
        'link',
        'links',
        'linux',
        'list',
        'lists',
        'log',
        'log-in',
        'log-out',
        'log_in',
        'log_out',
        'login',
        'logout',
        'logs',
        'm',
        'mac',
        'mail',
        'mail1',
        'mail2',
        'mail3',
        'mail4',
        'mail5',
        'mailer',
        'mailing',
        'maintenance',
        'manager',
        'manual',
        'map',
        'maps',
        'marketing',
        'master',
        'me',
        'media',
        'member',
        'members',
        'message',
        'messages',
        'messenger',
        'microblog',
        'microblogs',
        'mine',
        'mis',
        'mob',
        'mobile',
        'movie',
        'movies',
        'mp3',
        'msg',
        'msn',
        'music',
        'musicas',
        'mx',
        'my',
        'mysql',
        'name',
        'named',
        'nan',
        'navi',
        'navigation',
        'net',
        'network',
        'new',
        'news',
        'newsletter',
        'nick',
        'nickname',
        'notes',
        'noticias',
        'notification',
        'notifications',
        'notify',
        'ns',
        'ns1',
        'ns10',
        'ns2',
        'ns3',
        'ns4',
        'ns5',
        'ns6',
        'ns7',
        'ns8',
        'ns9',
        'null',
        'oauth',
        'oauth_clients',
        'offer',
        'offers',
        'official',
        'old',
        'online',
        'openid',
        'operator',
        'order',
        'orders',
        'organization',
        'organizations',
        'overview',
        'owner',
        'owners',
        'page',
        'pager',
        'pages',
        'panel',
        'password',
        'payment',
        'perl',
        'phone',
        'photo',
        'photoalbum',
        'photos',
        'php',
        'phpmyadmin',
        'phppgadmin',
        'phpredisadmin',
        'pic',
        'pics',
        'ping',
        'plan',
        'plans',
        'plugin',
        'plugins',
        'policy',
        'pop',
        'pop3',
        'popular',
        'portal',
        'post',
        'postfix',
        'postmaster',
        'posts',
        'pr',
        'premium',
        'press',
        'price',
        'pricing',
        'privacy',
        'privacy-policy',
        'privacy_policy',
        'privacypolicy',
        'private',
        'product',
        'products',
        'profile',
        'project',
        'projects',
        'promo',
        'pub',
        'public',
        'purpose',
        'put',
        'python',
        'query',
        'random',
        'ranking',
        'read',
        'readme',
        'recent',
        'recruit',
        'recruitment',
        'register',
        'registration',
        'release',
        'remove',
        'replies',
        'report',
        'reports',
        'repositories',
        'repository',
        'req',
        'request',
        'requests',
        'reset',
        'roc',
        'rss',
        'ruby',
        'rule',
        'sag',
        'sale',
        'sales',
        'sample',
        'samples',
        'save',
        'school',
        'script',
        'scripts',
        'search',
        'secure',
        'security',
        'self',
        'send',
        'server',
        'server-info',
        'server-status',
        'service',
        'services',
        'session',
        'sessions',
        'setting',
        'settings',
        'setup',
        'share',
        'shop',
        'show',
        'sign-in',
        'sign-up',
        'sign_in',
        'sign_up',
        'signin',
        'signout',
        'signup',
        'site',
        'sitemap',
        'sites',
        'smartphone',
        'smtp',
        'soporte',
        'source',
        'spec',
        'special',
        'sql',
        'src',
        'ssh',
        'ssl',
        'ssladmin',
        'ssladministrator',
        'sslwebmaster',
        'staff',
        'stage',
        'staging',
        'start',
        'stat',
        'state',
        'static',
        'stats',
        'status',
        'store',
        'stores',
        'stories',
        'style',
        'styleguide',
        'stylesheet',
        'stylesheets',
        'subdomain',
        'subscribe',
        'subscriptions',
        'suporte',
        'support',
        'svn',
        'swf',
        'sys',
        'sysadmin',
        'sysadministrator',
        'system',
        'tablet',
        'tablets',
        'tag',
        'talk',
        'task',
        'tasks',
        'team',
        'teams',
        'tech',
        'telnet',
        'term',
        'terms',
        'terms-of-service',
        'terms_of_service',
        'termsofservice',
        'test',
        'test1',
        'test2',
        'test3',
        'teste',
        'testing',
        'tests',
        'theme',
        'themes',
        'thread',
        'threads',
        'tmp',
        'todo',
        'tool',
        'tools',
        'top',
        'topic',
        'topics',
        'tos',
        'tour',
        'translations',
        'trends',
        'tutorial',
        'tux',
        'tv',
        'twitter',
        'undef',
        'unfollow',
        'unsubscribe',
        'update',
        'upload',
        'uploads',
        'url',
        'usage',
        'user',
        'username',
        'users',
        'usuario',
        'vendas',
        'ver',
        'version',
        'video',
        'videos',
        'visitor',
        'watch',
        'weather',
        'web',
        'webhook',
        'webhooks',
        'webmail',
        'webmaster',
        'website',
        'websites',
        'welcome',
        'widget',
        'widgets',
        'wiki',
        'win',
        'windows',
        'word',
        'work',
        'works',
        'workshop',
        'ww',
        'wws',
        'www',
        'www1',
        'www2',
        'www3',
        'www4',
        'www5',
        'www6',
        'www7',
        'wwws',
        'wwww',
        'xfn',
        'xml',
        'xmpp',
        'xpg',
        'xxx',
        'yaml',
        'year',
        'yml',
        'you',
        'yourdomain',
        'yourname',
        'yoursite',
        'yourusername'
    ];

    public static function isCalendarSlugAvailable($slug, $checkDb = true, $exceptId = false)
    {
        if (in_array($slug, self::$reserved)) {
            return false;
        }

        if (strlen($slug) < 4) {
            return false;
        }

        if ($checkDb) {

            if ($exceptId) {
                $exist = Calendar::where('slug', $slug)->where('id', '!=', $exceptId)->first();
            } else {
                $exist = Calendar::where('slug', $slug)->first();
            }

            if ($exist) {
                return false;
            }
        }


        if (is_numeric($slug)) {
            return false;
        }

        // check if $slug has any special characters or any space. We will only allow alpha-numeric values
        return preg_match('/^[a-zA-Z0-9_-]+$/', $slug);
    }

    public static function isEventSlugAvailable($slug, $checkDb = true, $calendarId = null, $exceptId = null)
    {
        if (in_array($slug, self::$reserved)) {
            return false;
        }

        if (strlen($slug) < 4) {
            return false;
        }

        if ($checkDb) {
            $eventQuery = CalendarSlot::where('slug', $slug);

            if ($exceptId) {
                $eventQuery->where('id', '!=', $exceptId);
            }

            if ($calendarId) {
                $eventQuery->where('calendar_id', $calendarId);
            }

            $exist = $eventQuery->first();

            if ($exist) {
                return false;
            }
        }

        if (is_numeric($slug)) {
            return false;
        }

        // check if $slug has any special characters or any space. We will only allow alpha-numeric values
        return preg_match('/^[a-zA-Z0-9_-]+$/', $slug);
    }

    public static function getAppBaseUrl($extension = '')
    {
        return apply_filters('fluent_booking/admin_base_url', admin_url('admin.php?page=fluent-booking#/' . $extension), $extension);
    }

    public static function getAdminBookingUrl($bookingId)
    {
        return self::getAppBaseUrl('scheduled-events?booking_id=' . $bookingId);
    }

    public static function getUpgradeUrl()
    {
        return 'https://fluentbooking.com/pricing/?utm_source=plugin&utm_medium=wp_install&utm_campaign=fcal_upgrade&theme=' . self::getActiveThemeName();
    }

    public static function getNextBookingGroup()
    {
        $lastBooking = Booking::orderBy('group_id', 'desc')->first(['group_id']);

        if ($lastBooking) {
            return $lastBooking->group_id + 1;
        }

        return 1;
    }

    public static function getNextIndex()
    {
        static $index = 0;

        $index += 1;

        return $index;
    }

    public static function getGlobalPaymentSettings()
    {
        static $settings;

        if ($settings) {
            return $settings;
        }

        $settings = get_option('fluent_booking_global_payment_settings', []);

        return $settings;
    }

    public static function isPaymentEnabled($calendarEvent = null)
    {
        $settings = CurrenciesHelper::getGlobalCurrencySettings();
        if (Arr::get($settings, 'is_active') == 'yes') {
            return true;
        }

        if ($calendarEvent) {
            if ($calendarEvent->type != 'paid') {
                return false;
            }

            $exist = Meta::where('object_type', 'calendar_slot')
                ->where('object_id', $calendarEvent->id)
                ->where('key', 'payment_settings')
                ->first();

            return $exist && $exist->value && Arr::get($exist->value, 'enabled') == 'yes';
        }

        return false;
    }

    public static function isPaymentConfigured($method = 'stripe')
    {
        $settings = get_option('fluent_booking_payment_settings_' . $method, []);

        return Arr::get($settings, 'is_active', 'no') == 'yes';
    }

    /**
     * Sanitize form inputs recursively.
     *
     * @param $input
     *
     * @return mixed $input
     */
    public static function fluentbookingSanitizer($input, $attribute = null, $fields = [])
    {
        if (is_string($input)) {
            $element = Arr::get($fields, $attribute . '.element');

            if (in_array($element, ['post_content', 'rich_text_input'])) {
                return wp_kses_post($input);
            } elseif ('textarea' === $element) {
                $input = sanitize_textarea_field($input);
            } elseif ('input_email' === $element) {
                $input = strtolower(sanitize_text_field($input));
            } elseif ('input_url' === $element) {
                $input = sanitize_url($input);
            } else {
                $input = sanitize_text_field($input);
            }
        } elseif (is_array($input)) {
            foreach ($input as $key => &$value) {
                $attribute = $attribute ? $attribute . '[' . $key . ']' : $key;

                $value = self::fluentbookingSanitizer($value, $attribute, $fields);

                $attribute = null;
            }
        }

        return $input;
    }

    public static function getMeta($group, $objectId, $key, $withModel = false)
    {
        $meta = Meta::where('object_type', $group)
            ->where('object_id', $objectId)
            ->where('key', $key)
            ->first();

        if ($meta) {
            if ($withModel) {
                return $meta;
            }

            return $meta->value;
        }

        return null;
    }

    public static function updateMeta($group, $objectId, $key, $value)
    {
        $meta = self::getMeta($group, $objectId, $key, true);

        if ($meta) {
            $meta->value = $value;
            $meta->save();
            return $meta;
        }

        return Meta::create([
            'object_type' => $group,
            'key'         => $key,
            'object_id'   => $objectId,
            'value'       => $value
        ]);
    }

    public static function deleteMeta($group, $objectId, $key)
    {
        return Meta::where('object_type', $group)
            ->where('object_id', $objectId)
            ->where('key', $key)
            ->delete();
    }

    public static function getBookingMeta($eventId, $metaKey, $withModel = false)
    {
        $bookingMeta = BookingMeta::where('booking_id', $eventId)
            ->where('meta_key', $metaKey)
            ->first();

        if ($bookingMeta) {
            return $withModel ? $bookingMeta : $bookingMeta->value;
        }

        return null;
    }

    public static function updateBookingMeta($eventId, $metaKey, $value)
    {
        $bookingMeta = self::getBookingMeta($eventId, $metaKey, true);

        if ($bookingMeta) {
            $bookingMeta->value = $value;
            $bookingMeta->save();
            return $bookingMeta;
        }

        return BookingMeta::create([
            'booking_id' => $eventId,
            'meta_key'   => $metaKey, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
            'value'      => $value
        ]);
    }

    public static function getUserDisplayName($userId = null)
    {
        if (!$userId) {
            $userId = get_current_user_id();
        }

        if (!$userId) {
            return '';
        }

        $user = get_user_by('ID', $userId);

        return self::getDisplayNameFromUser($user);
    }

    public static function getDisplayNameFromUser($user)
    {
        if (!$user) {
            return '';
        }

        $firstName = is_object($user) ? ($user->first_name ?? '') : '';
        $lastName  = is_object($user) ? ($user->last_name ?? '') : '';

        $name = trim($firstName . ' ' . $lastName);

        if ($name !== '') {
            return $name;
        }

        $displayName = is_object($user) ? ($user->display_name ?? '') : '';

        return (string) $displayName;
    }

    public static function getUserEmail($userId = null)
    {
        $userId = $userId ?: get_current_user_id();

        if (!$userId) {
            return '';
        }

        $user = get_user_by('ID', $userId);

        return $user->user_email;
    }

    public static function excerpt($text, $max_length = 160)
    {
        // Strip HTML tags and convert entities to their corresponding characters
        $text = html_entity_decode(wp_strip_all_tags($text));

        // Remove any line breaks, tabs, or extra whitespace
        $text = preg_replace('/\s+/', ' ', trim($text));

        if (mb_strlen($text) > $max_length) {
            $text = mb_substr($text, 0, $max_length);
            $text = preg_replace('/\s+\S+$/', '', $text) . '...';
        }

        return $text;
    }

    public static function generateSlotSlug($default, $calendar)
    {
        $original = sanitize_title($default, $default, 'display');

        $default = $original;

        $counter = 1;

        while (CalendarSlot::where('calendar_id', $calendar->id)->where('slug', $default)->first()) {
            $default = $original . '-' . $counter;
            $counter += 1;
        }

        return apply_filters('fluent_booking/slot_slug', $default, $original);
    }


    public static function getIp($defalt = '127.0.0.1')
    {
        static $ipAddress;

        if ($ipAddress) {
            return $ipAddress;
        }

        if (empty($_SERVER['REMOTE_ADDR'])) {
            // It's a local cli request
            return $defalt;
        }

        $ipAddress = '';

        $serverData = $_SERVER;
        $HTTP_CF_CONNECTING_IP = Arr::get($serverData, 'HTTP_CF_CONNECTING_IP');
        $RemoteAddr = Arr::get($serverData, 'REMOTE_ADDR');
        $clientIp = Arr::get($serverData, 'HTTP_CLIENT_IP');
        $HTTP_X_FORWARDED_FOR = Arr::get($serverData, 'HTTP_X_FORWARDED_FOR');
        if ($HTTP_CF_CONNECTING_IP) {
            //If it's a valid Cloudflare request

            if (self::isCfIp($RemoteAddr)) {
                //Use the CF-Connecting-IP header.
                $ipAddress = $HTTP_CF_CONNECTING_IP;
            } else {
                //If it isn't valid, then use REMOTE_ADDR.
                $ipAddress = $RemoteAddr;
            }
        } else if ($RemoteAddr == '127.0.0.1') {
            // most probably it's local reverse proxy
            if ($clientIp) {
                $ipAddress = $clientIp;
            } else if ($HTTP_X_FORWARDED_FOR) {
                $ipAddress = (string)rest_is_ip_address(trim(current(preg_split('/,/', sanitize_text_field($HTTP_X_FORWARDED_FOR)))));
            }
        }

        if (!$ipAddress) {
            $ipAddress = $RemoteAddr;
        }

        $ipAddress = preg_replace('/^(\d+\.\d+\.\d+\.\d+):\d+$/', '\1', $ipAddress);

        $ipAddress = apply_filters('fluent_booking/user_ip', $ipAddress, []);

        $ipAddress = sanitize_text_field(wp_unslash($ipAddress));

        return $ipAddress;
    }

    private static function isCfIp($ip = '')
    {
        if (!$ip) {
            $serverData = $_SERVER;
            $REMOTE_ADDR = Arr::get($serverData, 'REMOTE_ADDR');
            $ip = $REMOTE_ADDR;
        }
        $cloudflareIPRanges = array(
            '173.245.48.0/20',
            '103.21.244.0/22',
            '103.22.200.0/22',
            '103.31.4.0/22',
            '141.101.64.0/18',
            '108.162.192.0/18',
            '190.93.240.0/20',
            '188.114.96.0/20',
            '197.234.240.0/22',
            '198.41.128.0/17',
            '162.158.0.0/15',
            '104.16.0.0/13',
            '104.24.0.0/14',
            '172.64.0.0/13',
            '131.0.72.0/22',
        );
        //Make sure that the request came via Cloudflare.
        foreach ($cloudflareIPRanges as $range) {
            //Use the ip_in_range function from Joomla.
            if (self::ipInRange($ip, $range)) {
                //IP is valid. Belongs to Cloudflare.
                return true;
            }
        }

        return false;
    }

    private static function ipInRange($ip, $range)
    {
        if (strpos($range, '/') !== false) {
            // $range is in IP/NETMASK format
            list($range, $netmask) = explode('/', $range, 2);
            if (strpos($netmask, '.') !== false) {
                // $netmask is a 255.255.0.0 format
                $netmask = str_replace('*', '0', $netmask);
                $netmask_dec = ip2long($netmask);
                return ((ip2long($ip) & $netmask_dec) == (ip2long($range) & $netmask_dec));
            } else {
                // $netmask is a CIDR size block
                // fix the range argument
                $x = explode('.', $range);
                while (count($x) < 4) $x[] = '0';
                list($a, $b, $c, $d) = $x;
                $range = sprintf("%u.%u.%u.%u", empty($a) ? '0' : $a, empty($b) ? '0' : $b, empty($c) ? '0' : $c, empty($d) ? '0' : $d);
                $range_dec = ip2long($range);
                $ip_dec = ip2long($ip);

                # Strategy 1 - Create the netmask with 'netmask' 1s and then fill it to 32 with 0s
                #$netmask_dec = bindec(str_pad('', $netmask, '1') . str_pad('', 32-$netmask, '0'));

                # Strategy 2 - Use math to create it
                $wildcard_dec = pow(2, (32 - $netmask)) - 1;
                $netmask_dec = ~$wildcard_dec;

                return (($ip_dec & $netmask_dec) == ($range_dec & $netmask_dec));
            }
        } else {
            // range might be 255.255.*.* or 1.2.3.0-1.2.3.255
            if (strpos($range, '*') !== false) { // a.b.*.* format
                // Just convert to A-B format by setting * to 0 for A and 255 for B
                $lower = str_replace('*', '0', $range);
                $upper = str_replace('*', '255', $range);
                $range = "$lower-$upper";
            }

            if (strpos($range, '-') !== false) { // A-B format
                list($lower, $upper) = explode('-', $range, 2);
                $lower_dec = (float)sprintf("%u", ip2long($lower));
                $upper_dec = (float)sprintf("%u", ip2long($upper));
                $ip_dec = (float)sprintf("%u", ip2long($ip));
                return (($ip_dec >= $lower_dec) && ($ip_dec <= $upper_dec));
            }
            return false;
        }
    }

    public static function fcal_sanitize_html($html)
    {
        if (!$html) {
            return $html;
        }

        // Return $html if it's just a plain text
        if (!preg_match('/<[^>]*>/', $html)) {
            return $html;
        }

        $tags = wp_kses_allowed_html('post');
        $tags['style'] = [
            'types' => [],
        ];
        // iframe
        $tags['iframe'] = [
            'width'           => [],
            'height'          => [],
            'src'             => [],
            'title'           => [],
            'frameborder'     => [],
            'allow'           => [],
            'class'           => [],
            'id'              => [],
            'allowfullscreen' => [],
            'style'           => [],
        ];
        //button
        $tags['button'] = [
            'onclick' => []
        ];

        //svg
        if (empty($tags['svg'])) {
            $svg_args = [
                'svg'   => [
                    'class'           => true,
                    'aria-hidden'     => true,
                    'aria-labelledby' => true,
                    'role'            => true,
                    'xmlns'           => true,
                    'width'           => true,
                    'height'          => true,
                    'viewbox'         => true,
                ],
                'g'     => ['fill' => true],
                'title' => ['title' => true],
                'path'  => [
                    'd'         => true,
                    'fill'      => true,
                    'transform' => true,
                ],
            ];
            $tags = array_merge($tags, $svg_args);
        }

        $tags = apply_filters('fluent_booking/allowed_html_tags', $tags);

        return wp_kses($html, $tags);
    }

    /**
     * Sanitize inputs recursively.
     *
     * @param array $input
     * @param array $sanitizeMap
     *
     * @return array $input
     */
    public static function fcal_backend_sanitizer($inputs, $sanitizeMap = [])
    {
        $originalValues = $inputs;
        foreach ($inputs as $key => &$value) {
            if (is_array($value)) {
                $value = self::fcal_backend_sanitizer($value, $sanitizeMap);
            } else {
                $method = Arr::get($sanitizeMap, $key);
                if (!$method) {
                    continue;
                }
                if (is_callable($method)) {
                    $value = call_user_func($method, $value);
                } elseif (method_exists(self::class, $method)) {
                    $value = call_user_func([self::class, $method], $value);
                }
            }
        }

        return apply_filters('fluent_booking/backend_sanitized_values', $inputs, $originalValues);
    }

    /**
     * Recursively implode a multi-dimentional array
     *
     * @param string $glue
     * @param array $array
     *
     * @return string
     */
    public static function fcalImplodeRecursive($glue, array $array)
    {
        $fn = function ($glue, array $array) use (&$fn) {
            $result = '';
            foreach ($array as $item) {
                if (is_array($item)) {
                    $result .= $fn($glue, $item);
                } else {
                    $result .= $glue . $item;
                }
            }

            return $result;
        };

        return ltrim($fn($glue, $array), $glue);
    }

    public static function getEventColors()
    {
        return apply_filters('fluent_booking/event_colors', [
            [
                'label' => __('Red-Orange', 'fluent-booking'),
                'value' => '#ff4f00'
            ],
            [
                'label' => __('Deep Lilac', 'fluent-booking'),
                'value' => '#e55cff'
            ],
            [
                'label' => __('Purple', 'fluent-booking'),
                'value' => '#8247f5'
            ],
            [
                'label' => __('Vivid Blue', 'fluent-booking'),
                'value' => '#0099ff'
            ],
            [
                'label' => __('Cyan', 'fluent-booking'),
                'value' => '#0ae8f0'
            ],
            [
                'label' => __('Emerald Green', 'fluent-booking'),
                'value' => '#17e885'
            ],
            [
                'label' => __('Lime Green', 'fluent-booking'),
                'value' => '#ccf000'
            ],
            [
                'label' => __('Amber', 'fluent-booking'),
                'value' => '#ffa600'
            ]
        ]);
    }

    public static function getMeetingDurations()
    {
        return apply_filters('fluent_booking/meeting_durations_schema', [
            [
                'value' => '15',
                'label' => __('15 Minutes', 'fluent-booking')
            ],
            [
                'value' => '30',
                'label' => __('30 Minutes', 'fluent-booking')
            ],
            [
                'value' => '45',
                'label' => __('45 Minutes', 'fluent-booking')
            ],
            [
                'value' => '60',
                'label' => __('60 Minutes', 'fluent-booking')
            ],
            [
                'value' => 'custom',
                'label' => __('Custom', 'fluent-booking')
            ]
        ]);
    }

    public static function getMeetingMultiDurations()
    {
        return apply_filters('fluent_booking/meeting_multi_durations_schema', [
            [
                'value' => '5',
                'label' => __('5 Minutes', 'fluent-booking')
            ],
            [
                'value' => '10',
                'label' => __('10 Minutes', 'fluent-booking')
            ],
            [
                'value' => '15',
                'label' => __('15 Minutes', 'fluent-booking')
            ],
            [
                'value' => '30',
                'label' => __('30 Minutes', 'fluent-booking')
            ],
            [
                'value' => '45',
                'label' => __('45 Minutes', 'fluent-booking')
            ],
            [
                'value' => '50',
                'label' => __('50 Minutes', 'fluent-booking')
            ],
            [
                'value' => '60',
                'label' => __('60 Minutes', 'fluent-booking')
            ],
            [
                'value' => '90',
                'label' => __('90 Minutes', 'fluent-booking')
            ],
            [
                'value' => '120',
                'label' => __('120 Minutes', 'fluent-booking')
            ],
            [
                'value' => '150',
                'label' => __('150 Minutes', 'fluent-booking')
            ],
            [
                'value' => '180',
                'label' => __('180 Minutes', 'fluent-booking')
            ],
            [
                'value' => '240',
                'label' => __('240 Minutes', 'fluent-booking')
            ],
            [
                'value' => '480',
                'label' => __('480 Minutes', 'fluent-booking')
            ]
        ]);
    }

    public static function getDurationLookup($multiDuration = false)
    {
        $durations = $multiDuration ? self::getMeetingMultiDurations() : self::getMeetingDurations();

        $durationLookup = [];
        foreach ($durations as $duration) {
            $durationLookup[$duration['value']] = $duration['label'];
        }

        return $durationLookup;
    }

    public static function formatDuration($totalMinutes)
    {
        $days = floor($totalMinutes / 1440); // 1440 minutes in a day
        $hours = floor(($totalMinutes % 1440) / 60);
        $minutes = $totalMinutes % 60;

        $formattedDuration = [];
        if ($days > 0) {
            $unit = $days > 1 ? __('Days', 'fluent-booking') : __('Day', 'fluent-booking');
            $formattedDuration[] = $days . ' ' . $unit;
        }

        if ($hours > 0) {
            $unit = $hours > 1 ? __('Hours', 'fluent-booking') : __('Hour', 'fluent-booking');
            $formattedDuration[] = $hours . ' ' . $unit;
        }

        if ($minutes > 0 || empty($formattedDuration)) {
            $unit = $minutes > 1 ? __('Minutes', 'fluent-booking') : __('Minute', 'fluent-booking');
            $formattedDuration[] = $minutes . ' ' . $unit;
        }

        return implode(' ', $formattedDuration);
    }

    public static function getBufferTimes()
    {
        return apply_filters('fluent_booking/buffer_times_schema', [
            [
                'value' => '0',
                'label' => __('No buffer time', 'fluent-booking')
            ],
            [
                'value' => '5',
                'label' => __('5 Minutes', 'fluent-booking')
            ],
            [
                'value' => '10',
                'label' => __('10 Minutes', 'fluent-booking')
            ],
            [
                'value' => '15',
                'label' => __('15 Minutes', 'fluent-booking')
            ],
            [
                'value' => '20',
                'label' => __('20 Minutes', 'fluent-booking')
            ],
            [
                'value' => '30',
                'label' => __('30 Minutes', 'fluent-booking')
            ],
            [
                'value' => '45',
                'label' => __('45 Minutes', 'fluent-booking')
            ],
            [
                'value' => '60',
                'label' => __('60 Minutes', 'fluent-booking')
            ],
            [
                'value' => '90',
                'label' => __('90 Minutes', 'fluent-booking')
            ],
            [
                'value' => '120',
                'label' => __('120 Minutes', 'fluent-booking')
            ]
        ]);
    }

    public static function getSlotIntervals()
    {
        return apply_filters('fluent_booking/slot_intervals_schema', [
            [
                'value' => '',
                'label' => __('Use event length (default)', 'fluent-booking')
            ],
            [
                'value' => '5',
                'label' => __('5 Minutes', 'fluent-booking')
            ],
            [
                'value' => '10',
                'label' => __('10 Minutes', 'fluent-booking')
            ],
            [
                'value' => '15',
                'label' => __('15 Minutes', 'fluent-booking')
            ],
            [
                'value' => '20',
                'label' => __('20 Minutes', 'fluent-booking')
            ],
            [
                'value' => '30',
                'label' => __('30 Minutes', 'fluent-booking')
            ],
            [
                'value' => '45',
                'label' => __('45 Minutes', 'fluent-booking')
            ],
            [
                'value' => '60',
                'label' => __('60 Minutes', 'fluent-booking')
            ],
            [
                'value' => '75',
                'label' => __('75 Minutes', 'fluent-booking')
            ],
            [
                'value' => '90',
                'label' => __('90 Minutes', 'fluent-booking')
            ],
            [
                'value' => '105',
                'label' => __('105 Minutes', 'fluent-booking')
            ],
            [
                'value' => '120',
                'label' => __('120 Minutes', 'fluent-booking')
            ]
        ]);
    }

    public static function getBookingStatusChangingTimes()
    {
        return apply_filters('fluent_booking/booking_status_changing_times_schema', [
            [
                'value' => '5',
                'label' => __('5 Minutes', 'fluent-booking')
            ],
            [
                'value' => '10',
                'label' => __('10 Minutes', 'fluent-booking')
            ],
            [
                'value' => '20',
                'label' => __('20 Minutes', 'fluent-booking')
            ],
            [
                'value' => '30',
                'label' => __('30 Minutes', 'fluent-booking')
            ],
            [
                'value' => '40',
                'label' => __('40 Minutes', 'fluent-booking')
            ],
            [
                'value' => '50',
                'label' => __('50 Minutes', 'fluent-booking')
            ],
            [
                'value' => '60',
                'label' => __('1 Hour', 'fluent-booking')
            ],
            [
                'value' => '120',
                'label' => __('2 Hours', 'fluent-booking')
            ],
            [
                'value' => '180',
                'label' => __('3 Hours', 'fluent-booking')
            ],
            [
                'value' => '360',
                'label' => __('6 Hours', 'fluent-booking')
            ],
            [
                'value' => '720',
                'label' => __('12 Hours', 'fluent-booking')
            ],
            [
                'value' => '1440',
                'label' => __('1 Day', 'fluent-booking')
            ],
            [
                'value' => '2880',
                'label' => __('2 Days', 'fluent-booking')
            ]
        ]);
    }

    public static function getBookingPeriodOptions()
    {
        return apply_filters('fluent_booking/booking_period_options', [
            'upcoming'  => __('Upcoming', 'fluent-booking'),
            'completed' => __('Completed', 'fluent-booking'),
            'pending'   => __('Pending', 'fluent-booking'),
            'cancelled' => __('Cancelled', 'fluent-booking'),
            'all'       => __('All', 'fluent-booking'),
        ]);
    }

    public static function getWeekSelectTimes()
    {
        return apply_filters('fluent_booking/week_select_times_schema', [
            'start' => '00:00',
            'step'  => '00:15',
            'end'   => '23:45'
        ]);
    }

    public static function getOverrideSelectTimes()
    {
        return apply_filters('fluent_booking/override_select_times_schema', [
            'start' => '00:00',
            'step'  => '00:15',
            'end'   => '23:45'
        ]);
    }

    public static function getWeeklyScheduleSchema()
    {
        return apply_filters('fluent_booking/weekly_schedule_schema', [
            'sun' => [
                'enabled' => false,
                'slots'   => []
            ],
            'mon' => [
                'enabled' => true,
                'slots'   => [
                    ['start' => '09:00', 'end' => '17:00']
                ],
            ],
            'tue' => [
                'enabled' => true,
                'slots'   => [
                    ['start' => '09:00', 'end' => '17:00']
                ],
            ],
            'wed' => [
                'enabled' => true,
                'slots'   => [
                    ['start' => '09:00', 'end' => '17:00']
                ],
            ],
            'thu' => [
                'enabled' => true,
                'slots'   => [
                    ['start' => '09:00', 'end' => '17:00']
                ],
            ],
            'fri' => [
                'enabled' => true,
                'slots'   => [
                    ['start' => '09:00', 'end' => '17:00']
                ],
            ],
            'sat' => [
                'enabled' => false,
                'slots'   => []
            ],
        ]);
    }

    public static function getCustomFieldTypes()
    {
        return apply_filters('fluent_booking/custom_fields_types', [
            [
                'value' => 'email',
                'label' => __('Email', 'fluent-booking')
            ],
            [
                'value' => 'text',
                'label' => __('Text', 'fluent-booking')
            ],
            [
                'value' => 'textarea',
                'label' => __('Textarea', 'fluent-booking')
            ],
            [
                'value' => 'number',
                'label' => __('Number', 'fluent-booking')
            ],
            [
                'value' => 'phone',
                'label' => __('Phone', 'fluent-booking')
            ],
            [
                'value' => 'radio',
                'label' => __('Radio', 'fluent-booking')
            ],
            [
                'value' => 'dropdown',
                'label' => __('Select', 'fluent-booking')
            ],
            [
                'value' => 'multi-select',
                'label' => __('Multi Select', 'fluent-booking')
            ],
            [
                'value' => 'checkbox',
                'label' => __('Checkbox', 'fluent-booking')
            ],
            [
                'value' => 'checkbox-group',
                'label' => __('Checkbox Group', 'fluent-booking')
            ],
            [
                'value' => 'date',
                'label' => __('Date', 'fluent-booking')
            ],
            [
                'value' => 'file',
                'label' => __('File', 'fluent-booking')
            ],
            [
                'value' => 'hidden',
                'label' => __('Hidden', 'fluent-booking')
            ],
            [
                'value' => 'terms-and-conditions',
                'label' => __('Terms & Conditions', 'fluent-booking')
            ]
        ]);
    }

    public static function getDefaultTermsAndConditions()
    {
        $termsAndConditions = __('I have read and agree to the <a href="#" target="_blank" rel="noopener">Terms and Conditions</a> and <a href="#" target="_blank" rel="noopener">Privacy Policy</a>.', 'fluent-booking');

        return apply_filters('fluent_booking/default_terms_and_conditions', $termsAndConditions);
    }

    public static function getDefaultEmailNotificationSettings()
    {
        $assetUrl = App::getInstance()['url.assets'];

        $checkImage = $assetUrl . 'images/check-mark.png';
        $cancelImage = $assetUrl . 'images/cancel-mark.png';
        $scheduleImage = $assetUrl . 'images/schedule-mark.png';

        return apply_filters('fluent_booking/default_email_notification_settings', [
            'booking_conf_attendee'    => [
                'enabled' => true,
                'title'   => __('Booking Confirmation Email to Attendee', 'fluent-booking'),
                'email'   => [
                    'subject' => 'Booking Confirmation between {{host.name}} & {{guest.full_name}}',
                    'body'    => '<p style="text-align: center;"><img class="alignnone  wp-image-76" src="' . $checkImage . '" alt="" width="60" height="60" /></p><h2 class="p1" style="text-align: center;">Your event has been scheduled</h2><hr /><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{host.name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_guest_timezone}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} - you</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Additional notes</strong></p><p>{{guest.note}}</p><hr /><p style="text-align: center;">' . __('Need to make a change?', 'fluent-booking') . ' <a href="##booking.reschedule_url##">' . __('Reschedule', 'fluent-booking') . '</a> or <a href="##booking.cancelation_url##">' . __('Cancel', 'fluent-booking') . '</p><hr/>' . self::getAddToCalendarHtml($assetUrl)
                ],
            ],
            'booking_conf_host'        => [
                'enabled' => true,
                'is_host' => true,
                'title'   => __('Booking Confirmation Email to Organizer (You)', 'fluent-booking'),
                'email'   => [
                    'additional_recipients' => '',
                    'subject'               => 'New Booking: {{guest.full_name}} @ {{booking.start_date_time_for_host}}',
                    'body'                  => '<p style="text-align: center;"><img class="alignnone  wp-image-76" src="' . $checkImage . '" alt="" width="60" height="60" /></p><h2 class="p1" style="text-align: center;">A new event has been scheduled</h2><hr /><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_host_timezone}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} ({{guest.email}}) - Guest</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Note</strong></p><p>{{guest.note}}</p><p><strong>Additional Data</strong></p><p>{{guest.form_data_html}}</p><hr /><p style="text-align: center;"><a href="##booking.admin_booking_url##">View on the Website</a></p>'
                ],
            ],
            'reminder_to_attendee'     => [
                'enabled' => false,
                'title'   => __('Configure Meeting Reminder to Attendee', 'fluent-booking'),
                'email'   => [
                    'subject' => 'Meeting Reminder with {{host.name}} @ {{booking.start_date_time_for_attendee}}',
                    'body'    => '<h2 style="text-align: center;">Reminder: Your meeting will start in {{booking.start_time_human_format}}</h2><hr /><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{host.name}}</p><h3><strong>When</strong></h3><p>{{booking.full_start_end_guest_timezone}}</p><h3><strong>Who</strong></h3><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} - you</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Additional notes</strong></p><p>{{guest.note}}</p><hr /><p style="text-align: center;">' . __('Need to make a change?', 'fluent-booking') . ' <a href="##booking.reschedule_url##">' . __('Reschedule', 'fluent-booking') . '</a> or <a href="##booking.cancelation_url##">' . __('Cancel', 'fluent-booking') . '</a></p>',
                    'times'   => [
                        [
                            'unit'  => 'minutes',
                            'value' => 15,
                        ]
                    ]
                ],
            ],
            'reminder_to_host'         => [
                'enabled' => false,
                'is_host' => true,
                'title'   => __('Configure Meeting Reminder to Organizer (You)', 'fluent-booking'),
                'email'   => [
                    'additional_recipients' => '',
                    'subject'               => 'Meeting Reminder with {{host.name}} @ {{booking.start_date_time_for_host}}',
                    'body'                  => '<h2 style="text-align: center;">Reminder: Your meeting will start in {{booking.start_time_human_format}}</h2><hr /><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_host_timezone}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} ({{guest.email}}) - Guest</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Note</strong></p><p>{{guest.note}}</p><p><strong>Additional Data</strong></p><p>{{guest.form_data_html}}</p><hr /><p style="text-align: center;"><a href="##booking.admin_booking_url##">View on the Website</a></p>',
                    'times'                 => [
                        [
                            'unit'  => 'minutes',
                            'value' => 15,
                        ]
                    ]
                ],
            ],
            'cancelled_by_attendee'    => [
                'enabled' => true,
                'is_host' => true,
                'title'   => __('Booking Cancelled by Attendee (email to Organizer)', 'fluent-booking'),
                'email'   => [
                    'additional_recipients' => '',
                    'subject'               => 'A booking was cancelled with {{guest.full_name}}',
                    'body'                  => '<p style="text-align: center;"><img class="alignnone  wp-image-76" src="' . $cancelImage . '" alt="" width="60" height="60" /></p><h2 style="text-align: center;">Booking Cancellation</h2><hr /><p>A scheduled meeting has been canceled. Here are the details:</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_host_timezone}} <span style="color: #ff0000;"><strong>(cancelled)</strong></span></p><p><strong>Cancellation Reason</strong></p><p>{{booking.cancel_reason}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} ({{guest.email}}) - Guest</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Note</strong></p><p>{{guest.note}}</p><p><strong>Additional Data</strong></p><p>{{guest.form_data_html}}</p><hr /><p style="text-align: center;"><a href="##booking.admin_booking_url##">View on the Website</a></p>'
                ],
            ],
            'cancelled_by_host'        => [
                'enabled' => true,
                'title'   => __('Booking Cancelled by Organizer (email to Attendee)', 'fluent-booking'),
                'email'   => [
                    'subject' => 'Your booking was cancelled with {{host.name}}',
                    'body'    => '<p style="text-align: center;"><img class="alignnone  wp-image-76" src="' . $cancelImage . '" alt="" width="60" height="60" /></p><h2 style="text-align: center;">Booking Cancellation</h2><hr /><p>Your scheduled meeting has been canceled. Here are the details:</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_host_timezone}} <span style="color: #ff0000;"><strong>(cancelled)</strong></span></p><p><strong>Cancellation Reason</strong></p><p>{{booking.cancel_reason}}</p>'
                ],
            ],
            'rescheduled_by_attendee'  => [
                'enabled' => true,
                'is_host' => true,
                'title'   => __('Booking Rescheduled by Attendee (email to Organizer)', 'fluent-booking'),
                'email'   => [
                    'additional_recipients' => '',
                    'subject'               => 'A booking was rescheduled with {{guest.full_name}}',
                    'body'                  => '<p style="text-align: center;"><img class="alignnone  wp-image-76" src="' . $scheduleImage . '" alt="" width="60" height="60" /></p><h2 style="text-align: center;">Booking Rescheduled</h2><hr /><p>A scheduled meeting has been rescheduled. Here are the details:</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>New Time: {{booking.full_start_end_host_timezone}} <span style="color: #ff0000;"><strong>(new)</strong></span></p><p>Previous Time: {{booking.previous_meeting_time}}</p><p><strong>Rescheduling Reason</strong></p><p>{{booking.reschedule_reason}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} ({{guest.email}}) - Guest</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Note</strong></p><p>{{guest.note}}</p><p><strong>Additional Data</strong></p><p>{{guest.form_data_html}}</p><hr /><p style="text-align: center;"><a href="##booking.admin_booking_url##">View on the Website</a></p>'
                ],
            ],
            'rescheduled_by_host'      => [
                'enabled' => true,
                'title'   => __('Booking Rescheduled by Organizer (email to Attendee)', 'fluent-booking'),
                'email'   => [
                    'subject' => 'Your booking was rescheduled with {{host.name}}',
                    'body'    => '<p style="text-align: center;"><img class="alignnone  wp-image-76" src="' . $scheduleImage . '" alt="" width="60" height="60" /></p><h2 style="text-align: center;">Booking Rescheduled</h2><hr /><p>Your scheduled meeting has been rescheduled. Here are the details:</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>New Time: {{booking.full_start_end_host_timezone}} <span style="color: #ff0000;"><strong>(new)</strong></span></p><p>Previous Time: {{booking.previous_meeting_time_guest_timezone}}</p><p><strong>Rescheduling Reason</strong></p><p>{{booking.reschedule_reason}}</p><hr /><p style="text-align: center;">' . __('Need to make a change?', 'fluent-booking') . ' <a href="##booking.reschedule_url##">' . __('Reschedule', 'fluent-booking') . '</a> or <a href="##booking.cancelation_url##">' . __('Cancel', 'fluent-booking') . '</a></p><hr/>' . self::getAddToCalendarHtml($assetUrl)
                ],
            ],
            'booking_request_host'     => [
                'enabled' => true,
                'is_host' => true,
                'title'   => __('Booking Approval Request to Host (email to Organizer)', 'fluent-booking'),
                'email'   => [
                    'additional_recipients' => '',
                    'subject'               => 'Awaiting Approval: {{guest.full_name}} @ {{booking.start_date_time_for_host}}',
                    'body'                  => '<p style="text-align: center;"><img class="alignnone  wp-image-76" src="' . $scheduleImage . '" alt="" width="60" height="60" /></p><h2 class="p1" style="text-align: center;">A booking is still waiting for your approval</h2><hr /><p>Someone has requested to schedule an event on your calendar. Here are the details:</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_host_timezone}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} ({{guest.email}}) - Guest</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Note</strong></p><p>{{guest.note}}</p><p><strong>Additional Data</strong></p><p>{{guest.form_data_html}}</p><hr />' . self::getConfirmAndRejectButton($assetUrl) . '<p style="text-align: center;"><a href="##booking.admin_booking_url##">View on the Website</a></p>'
                ],
            ],
            'booking_request_attendee' => [
                'enabled' => true,
                'title'   => __('Booking Submission Confirmation (email to Attendee)', 'fluent-booking'),
                'email'   => [
                    'subject' => 'Booking Submitted: Meeting between {{host.name}} & {{guest.full_name}}',
                    'body'    => '<p style="text-align: center;"><img class="alignnone  wp-image-76" src="' . $scheduleImage . '" alt="" width="60" height="60" /></p><h2 class="p1" style="text-align: center;">Your booking has been submitted</h2><hr /><p>Please wait for the host to confirm your booking.</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{host.name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_guest_timezone}}</p><p><strong>Who</strong></p><ul><li>{{host.name}} - Organizer</li><li>{{guest.full_name}} - you</li></ul><p><strong>Where</strong></p><p>{{booking.location_details_html}}</p><p><strong>Additional notes</strong></p><p>{{guest.note}}</p><hr /><p style="text-align: center;">' . __('Need to make a change?', 'fluent-booking') . ' <a href="##booking.reschedule_url##">' . __('Reschedule', 'fluent-booking') . '</a> or <a href="##booking.cancelation_url##">' . __('Cancel', 'fluent-booking') . '</p>'
                ],
            ],
            'declined_by_host'         => [
                'enabled' => true,
                'title'   => __('Booking Declined by Organizer (email to Attendee)', 'fluent-booking'),
                'email'   => [
                    'subject' => 'Booking Declined: Your booking was declined with {{host.name}}',
                    'body'    => '<p style="text-align: center;"><img class="alignnone  wp-image-76" src="' . $cancelImage . '" alt="" width="60" height="60" /></p><h2 style="text-align: center;">Booking Declined</h2><hr /><p>Your booking request has been declined. Here are the details:</p><p><strong>Event Name</strong></p><p>{{booking.event_name}} with {{guest.full_name}}</p><p><strong>When</strong></p><p>{{booking.full_start_end_host_timezone}} <span style="color: #ff0000;"><strong>(declined)</strong></span></p><p><strong>Reason</strong></p><p>{{booking.reject_reason}}</p>'
                ],
            ],
        ]);
    }

    public static function getAddToCalendarHtml($assetUrl = '')
    {
        $assetUrl = $assetUrl ?: App::getInstance()['url.assets'];

        $html = '<table style="margin: 0 auto; border: none;"><tbody><tr><td style="border: none; font-size: 1rem;">' . __('Add to calendar', 'fluent-booking') . '</td><td style="border: 1px solid black; padding: 5px 5px 0 5px;"><a href="##add_to_g_calendar_url##"><img width="20" height="20" src="' . $assetUrl . 'images/g-icon.png" alt="Google Calendar" /></a></td><td style="border: 1px solid black; padding: 5px 5px 0 5px;"><a href="##add_to_ol_calendar_url##"><img width="20" height="20" src="' . $assetUrl . 'images/ol-icon.png" alt="Outlook" /></a></td><td style="border: 1px solid black; padding: 5px 5px 0 5px;"><a href="##add_to_ms_calendar_url##"><img width="20" height="20" src="' . $assetUrl . 'images/msoffice.png" alt="Microsoft Office" /></a></td><td style="border: 1px solid black; padding: 5px 5px 0 5px;"><a href="##add_to_ics_calendar_url##"><img width="20" height="20" src="' . $assetUrl . 'images/ics.png" alt="Other Calendar" /></a></td></tr></tbody></table>';

        return apply_filters('fluent_booking/add_to_calendar_html', $html);
    }

    public static function getConfirmAndRejectButton($assetUrl = '')
    {
        $assetUrl = $assetUrl ?: App::getInstance()['url.assets'];

        $html = '<table style="margin: 16px auto; border: none;"><tbody><tr><td style="border: none; border-radius: 3px;" align="center" valign="middle"><p style="display: inline-block; background: #292929; color: #ffffff; font-size: 14px; font-weight: 500; line-height: 16px; margin: 0; text-decoration: none; text-transform: none; padding: 10px 16px 10px 14px; border-radius: 6px; box-sizing: border-box; height: 36px;"><a href="##booking.booking_confirm_url##" style="color: #ffffff; text-decoration: none; display: flex; margin: auto;"><img src="' . $assetUrl . 'images/confirm-mark.png" style="height: 16px; width: 16px; margin-left: 0; margin-right: 0.5rem;" alt="" width="16px" data-bit="iit" />' . __('Confirm', 'fluent-booking') . '</a></p><p style="width: 16px; height: 16px; display: inline-block;"> </p><p style="display: inline-block; background: #ffffff; border: 1px solid #d1d5db; color: #ffffff; font-size: 14px; font-weight: 500; line-height: 16px; margin: 0; text-decoration: none; text-transform: none; padding: 10px 16px 10px 14px; border-radius: 6px; box-sizing: border-box; height: 36px;"><a href="##booking.booking_reject_url##" style="color: #292929; text-decoration: none; display: flex; margin: auto;"><img src="' . $assetUrl . 'images/reject-mark.png" style="height: 16px; width: 16px; margin-left: 0; margin-right: 8px;" alt="" width="16px" data-bit="iit" />' . __('Reject', 'fluent-booking') . '</a></p></td></tr></tbody></table>';

        return apply_filters('fluent_booking/confirm_and_reject_button_html', $html);
    }

    public static function getIframeHtml()
    {
        $html = '<iframe id="fluentbooking" loading="lazy" height="700px" width="100%" style="min-width:320px;height:700px;" frameborder="0" src="##landing_page_url##"></iframe>';

        return apply_filters('fluent_booking/get_iframe_html', $html);
    }

    public static function getEditorShortCodes($calendarEvent = null, $isHtmlSupported = false, $iframeHtml = '')
    {
        if (!$isHtmlSupported) {
            $groups = [
                'guest'   => [
                    'title'      => __('Attendee Data', 'fluent-booking'),
                    'key'        => 'guest',
                    'shortcodes' => [
                        '{{guest.first_name}}'  => __('Guest First Name', 'fluent-booking'),
                        '{{guest.last_name}}'   => __('Guest Last Name', 'fluent-booking'),
                        '{{guest.full_name}}'   => __('Guest Full Name', 'fluent-booking'),
                        '{{guest.email}}'       => __('Guest Email', 'fluent-booking'),
                        '{{guest.note}}'        => __('Guest Note', 'fluent-booking'),
                        '{{booking.phone}}'     => __('Guest Main Phone Number (if provided)', 'fluent-booking'),
                        '{{guest.timezone}}'    => __('Guest Timezone', 'fluent-booking'),
                        '{{guest.total_guest}}' => __('Total Guest Count', 'fluent-booking')
                    ]
                ],
                'booking' => [
                    'title'      => __('Booking Data', 'fluent-booking'),
                    'key'        => 'booking',
                    'shortcodes' => [
                        '{{booking.event_name}}'                                => __('Event Name', 'fluent-booking'),
                        '{{booking.description}}'                               => __('Event Description', 'fluent-booking'),
                        '{{booking.booking_title}}'                             => __('Booking Title', 'fluent-booking'),
                        '{{booking.additional_guests}}'                         => __('Additional Guests', 'fluent-booking'),
                        '{{booking.full_start_end_guest_timezone}}'             => __('Full Start Date Time (with guest timezone)', 'fluent-booking'),
                        '{{booking.full_start_end_host_timezone}}'              => __('Full Start Date Time (with host timezone)', 'fluent-booking'),
                        '{{booking.full_start_and_end_guest_timezone}}'         => __('Full Start & End Date Time (with guest timezone)', 'fluent-booking'),
                        '{{booking.full_start_and_end_host_timezone}}'          => __('Full Start & End Date Time (with host timezone)', 'fluent-booking'),
                        '{{booking.all_bookings_short_times_guest_timezone}}'   => __('All Bookings Short Times (with guest timezone)', 'fluent-booking'),
                        '{{booking.all_bookings_short_times_host_timezone}}'    => __('All Bookings Short Times (with host timezone)', 'fluent-booking'),
                        '{{booking.all_bookings_full_times_guest_timezone}}'    => __('All Bookings Full Times (with guest timezone)', 'fluent-booking'),
                        '{{booking.all_bookings_full_times_host_timezone}}'     => __('All Bookings Full Times (with host timezone)', 'fluent-booking'),
                        '{{booking.start_date_time}}'                           => __('Event Date Time (UTC)', 'fluent-booking'),
                        '{{booking.start_date_time_for_attendee}}'              => __('Event Date Time (with attendee timezone)', 'fluent-booking'),
                        '{{booking.start_date_time_for_host}}'                  => __('Event Date Time (with host timezone)', 'fluent-booking'),
                        '{{booking.start_date_time_for_attendee.format.Y-m-d}}' => __('Event Date Time (with attendee timezone) (Ex: 2024-05-20)', 'fluent-booking'),
                        '{{booking.start_date_time_for_host.format.Y-m-d}}'     => __('Event Date Time (with host timezone) (Ex: 2024-05-20)', 'fluent-booking'),
                        '{{booking.location_details_text}}'                     => __('Event Location Details', 'fluent-booking'),
                        '{{booking.cancel_reason}}'                             => __('Event Cancel Reason', 'fluent-booking'),
                        '{{booking.start_time_human_format}}'                   => __('Event Start Time (ex: 2 hours from now)', 'fluent-booking'),
                        '##booking.cancelation_url##'                           => __('Booking Cancellation URL', 'fluent-booking'),
                        '##booking.reschedule_url##'                            => __('Booking Reschedule URL', 'fluent-booking'),
                        '##booking.admin_booking_url##'                         => __('Booking Details Admin URL', 'fluent-booking'),
                        '{{booking.source_url}}'                                => __('Source URL', 'fluent-booking'),
                        '{{booking.utm_source}}'                                => __('UTM Source', 'fluent-booking'),
                        '{{booking.utm_medium}}'                                => __('UTM Medium', 'fluent-booking'),
                        '{{booking.utm_campaign}}'                              => __('UTM Campaign', 'fluent-booking'),
                        '{{booking.utm_term}}'                                  => __('UTM Term', 'fluent-booking'),
                        '{{booking.utm_content}}'                               => __('UTM Content', 'fluent-booking'),
                        '{{booking.booking_hash}}'                              => __('Unique Booking Hash', 'fluent-booking'),
                        '{{booking.reschedule_reason}}'                         => __('Event Reschedule Reason', 'fluent-booking'),
                        '{{booking.previous_meeting_date_time_host_timezone}}'  => __('Previous Meeting Date & Time (with host timezone)', 'fluent-booking'),
                        '{{booking.previous_meeting_date_time_guest_timezone}}' => __('Previous Meeting Date & Time (with guest timezone)', 'fluent-booking'),
                    ]
                ],
                'host'    => [
                    'title'      => __('Host Data', 'fluent-booking'),
                    'key'        => 'host',
                    'shortcodes' => [
                        '{{host.name}}'     => __('Host Name', 'fluent-booking'),
                        '{{host.email}}'    => __('Host Email', 'fluent-booking'),
                        '{{host.timezone}}' => __('Host Timezone', 'fluent-booking'),
                    ]
                ],
                'other'   => [
                    'title'      => __('Other', 'fluent-booking'),
                    'key'        => 'other',
                    'shortcodes' => [
                        '{{event.id}}'                => __('Event ID', 'fluent-booking'),
                        '{{calendar.id}}'             => __('Calendar ID', 'fluent-booking'),
                        '{{event.title}}'             => __('Event Title', 'fluent-booking'),
                        '{{calendar.title}}'          => __('Calendar Title', 'fluent-booking'),
                        '{{calendar.description}}'    => __('Calendar Description', 'fluent-booking'),
                        '{{add_booking_to_calendar}}' => __('Add Booking to Calendar', 'fluent-booking'),
                    ]
                ]
            ];
        } else {
            $groups = [
                'guest'   => [
                    'title'      => __('Attendee Data', 'fluent-booking'),
                    'key'        => 'guest',
                    'shortcodes' => [
                        '{{guest.first_name}}'     => __('Guest First Name', 'fluent-booking'),
                        '{{guest.last_name}}'      => __('Guest Last Name', 'fluent-booking'),
                        '{{guest.full_name}}'      => __('Guest Full Name', 'fluent-booking'),
                        '{{guest.email}}'          => __('Guest Email', 'fluent-booking'),
                        '{{booking.phone}}'        => __('Guest Main Phone Number (if provided)', 'fluent-booking'),
                        '{{guest.note}}'           => __('Guest Note', 'fluent-booking'),
                        '{{guest.timezone}}'       => __('Guest Timezone', 'fluent-booking'),
                        '{{guest.total_guest}}'    => __('Total Guest Count', 'fluent-booking')
                    ]
                ],
                'booking' => [
                    'title'      => __('Booking Data', 'fluent-booking'),
                    'key'        => 'booking',
                    'shortcodes' => [
                        '{{booking.event_name}}'                                => __('Event Name', 'fluent-booking'),
                        '{{booking.description}}'                               => __('Event Description', 'fluent-booking'),
                        '{{booking.booking_title}}'                             => __('Booking Title', 'fluent-booking'),
                        '{{booking.additional_guests}}'                         => __('Additional Guests', 'fluent-booking'),
                        '{{booking.full_start_end_guest_timezone}}'             => __('Full Start Date Time (with guest timezone)', 'fluent-booking'),
                        '{{booking.full_start_end_host_timezone}}'              => __('Full Start Date Time (with host timezone)', 'fluent-booking'),
                        '{{booking.full_start_and_end_guest_timezone}}'         => __('Full Start & End Date Time (with guest timezone)', 'fluent-booking'),
                        '{{booking.full_start_and_end_host_timezone}}'          => __('Full Start & End Date Time (with host timezone)', 'fluent-booking'),
                        '{{booking.all_bookings_short_times_guest_timezone}}'   => __('All Bookings Short Times (with guest timezone)', 'fluent-booking'),
                        '{{booking.all_bookings_short_times_host_timezone}}'    => __('All Bookings Short Times (with host timezone)', 'fluent-booking'),
                        '{{booking.all_bookings_full_times_guest_timezone}}'    => __('All Bookings Full Times (with guest timezone)', 'fluent-booking'),
                        '{{booking.all_bookings_full_times_host_timezone}}'     => __('All Bookings Full Times (with host timezone)', 'fluent-booking'),
                        '{{booking.start_date_time}}'                           => __('Event Date Time (UTC)', 'fluent-booking'),
                        '{{booking.start_date_time_for_attendee}}'              => __('Event Date Time (with guest timezone)', 'fluent-booking'),
                        '{{booking.start_date_time_for_host}}'                  => __('Event Date Time (with host timezone)', 'fluent-booking'),
                        '{{booking.start_date_time_for_attendee.format.Y-m-d}}' => __('Event Date Time (with attendee timezone) (Ex: 2024-05-20)', 'fluent-booking'),
                        '{{booking.start_date_time_for_host.format.Y-m-d}}'     => __('Event Date Time (with host timezone) (Ex: 2024-05-20)', 'fluent-booking'),
                        '{{booking.location_details_html}}'                     => __('Event Location Details (HTML)', 'fluent-booking'),
                        '{{booking.cancel_reason}}'                             => __('Event Cancel Reason', 'fluent-booking'),
                        '{{booking.start_time_human_format}}'                   => __('Event Start Time (ex: 2 hours from now)', 'fluent-booking'),
                        '##booking.cancelation_url##'                           => __('Booking Cancellation URL', 'fluent-booking'),
                        '##booking.reschedule_url##'                            => __('Booking Reschedule URL', 'fluent-booking'),
                        '##booking.admin_booking_url##'                         => __('Booking Details Admin URL', 'fluent-booking'),
                        '{{booking.source_url}}'                                => __('Source URL', 'fluent-booking'),
                        '{{booking.utm_source}}'                                => __('UTM Source', 'fluent-booking'),
                        '{{booking.utm_medium}}'                                => __('UTM Medium', 'fluent-booking'),
                        '{{booking.utm_campaign}}'                              => __('UTM Campaign', 'fluent-booking'),
                        '{{booking.utm_term}}'                                  => __('UTM Term', 'fluent-booking'),
                        '{{booking.utm_content}}'                               => __('UTM Content', 'fluent-booking'),
                        '{{booking.booking_hash}}'                              => __('Unique Booking Hash', 'fluent-booking'),
                        '{{booking.reschedule_reason}}'                         => __('Event Reschedule Reason', 'fluent-booking'),
                        '{{booking.previous_meeting_date_time_host_timezone}}'  => __('Previous Meeting Date & Time (with host timezone)', 'fluent-booking'),
                        '{{booking.previous_meeting_date_time_guest_timezone}}' => __('Previous Meeting Date & Time (with guest timezone)', 'fluent-booking'),
                    ]
                ],
                'host'    => [
                    'title'      => __('Host Data', 'fluent-booking'),
                    'key'        => 'host',
                    'shortcodes' => [
                        '{{host.name}}'     => __('Host Name', 'fluent-booking'),
                        '{{host.email}}'    => __('Host Email', 'fluent-booking'),
                        '{{host.timezone}}' => __('Host Timezone', 'fluent-booking'),
                    ]
                ],
                'other'   => [
                    'title'      => __('Other', 'fluent-booking'),
                    'key'        => 'other',
                    'shortcodes' => [
                        '{{event.id}}'                => __('Event ID', 'fluent-booking'),
                        '{{event.calendar_id}}'       => __('Calendar ID', 'fluent-booking'),
                        '{{event.title}}'             => __('Event Title', 'fluent-booking'),
                        '{{calendar.title}}'          => __('Calendar Title', 'fluent-booking'),
                        '{{calendar.description}}'    => __('Calendar Description', 'fluent-booking'),
                        '{{add_booking_to_calendar}}' => __('Add Booking to Calendar', 'fluent-booking'),
                    ]
                ]
            ];
        }

        if ($calendarEvent) {
            $customFields = BookingFieldService::getCustomFields($calendarEvent, true);
            foreach ($customFields as $fieldKey => $field) {
                $groups['booking']['shortcodes']['{{booking.custom.' . $fieldKey . '}}'] = $field['label'];
                if ($field['type'] == 'date') {
                    $groups['booking']['shortcodes']['{{booking.custom.' . $fieldKey . '.format.Y-m-d}}'] = $field['label'] . ' (Ex: 2024-05-20)';
                }
            }

            if (Helper::isPaymentEnabled($calendarEvent)) {
                $groups['payment'] = [
                    'title'      => __('Payment Data', 'fluent-booking'),
                    'key'        => 'payment',
                    'shortcodes' => [
                        '{{payment.payment_total}}'  => __('Payment Total', 'fluent-booking'),
                        '{{payment.payment_status}}' => __('Payment Status', 'fluent-booking'),
                        '{{payment.payment_method}}' => __('Payment Method', 'fluent-booking'),
                        '{{payment.currency}}'       => __('Currency', 'fluent-booking'),
                        '{{payment.payment_date}}'   => __('Payment Date', 'fluent-booking'),
                    ]
                ];

                if ($isHtmlSupported) {
                    $groups['payment']['shortcodes']['{{payment.receipt_html}}'] = __('Payment Receipt (HTML)', 'fluent-booking');
                }
            }

            if ($calendarEvent->isMultiHostsEvent()) {
                $totalhost = count($calendarEvent->getHostIds());
                for ($i = 1; $i < $totalhost; $i++) {
                    $groups['host']['shortcodes']['{{team_member.' . $i . '.name}}'] = __('Team Member ', 'fluent-booking') . $i . __(' Name', 'fluent-booking');
                    $groups['host']['shortcodes']['{{team_member.' . $i . '.email}}'] = __('Team Member ', 'fluent-booking') . $i . __(' Email', 'fluent-booking');
                }
            }
        }

        return apply_filters('fluent_booking/editor_shortcodes_groups', $groups, $calendarEvent, $isHtmlSupported);
    }

    public static function encryptKey($value)
    {
        if (!$value) {
            return $value;
        }

        if (!extension_loaded('openssl')) {
            return $value;
        }

        $salt = (defined('LOGGED_IN_SALT') && '' !== LOGGED_IN_SALT) ? LOGGED_IN_SALT : 'this-is-a-fallback-salt-but-not-secure';

        if (defined('FLUENT_BOOKING_ENCRYPTION_KEY')) {
            $key = FLUENT_BOOKING_ENCRYPTION_KEY;
        } else {
            $key = (defined('LOGGED_IN_KEY') && '' !== LOGGED_IN_KEY) ? LOGGED_IN_KEY : 'this-is-a-fallback-key-but-not-secure';
        }

        $method = 'aes-256-ctr';
        $ivlen = openssl_cipher_iv_length($method);
        $iv = openssl_random_pseudo_bytes($ivlen);

        $raw_value = openssl_encrypt($value . $salt, $method, $key, 0, $iv);
        if (!$raw_value) {
            return false;
        }

        return base64_encode($iv . $raw_value); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
    }

    public static function decryptKey($raw_value)
    {

        if (!$raw_value) {
            return $raw_value;
        }

        if (!extension_loaded('openssl')) {
            return $raw_value;
        }

        $raw_value = base64_decode($raw_value, true); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
        if ($raw_value === false) {
            return false;
        }

        $method = 'aes-256-ctr';
        $ivlen = openssl_cipher_iv_length($method);
        if ($ivlen === false || strlen($raw_value) <= $ivlen) {
            return false;
        }
        $iv = substr($raw_value, 0, $ivlen);

        $raw_value = substr($raw_value, $ivlen);

        if (defined('FLUENT_BOOKING_ENCRYPTION_KEY')) {
            $key = FLUENT_BOOKING_ENCRYPTION_KEY;
        } else {
            $key = (defined('LOGGED_IN_KEY') && '' !== LOGGED_IN_KEY) ? LOGGED_IN_KEY : 'this-is-a-fallback-key-but-not-secure';
        }

        $salt = (defined('LOGGED_IN_SALT') && '' !== LOGGED_IN_SALT) ? LOGGED_IN_SALT : 'this-is-a-fallback-salt-but-not-secure';

        $value = openssl_decrypt($raw_value, $method, $key, 0, $iv);
        if (!is_string($value) || substr($value, -strlen($salt)) !== $salt) {
            return false;
        }

        return substr($value, 0, -strlen($salt));
    }

    public static function debugLog($data)
    {
        if (defined('FLUENT_BOOKING_DEBUG') && FLUENT_BOOKING_DEBUG) {
            error_log(print_r($data, true)); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log,WordPress.PHP.DevelopmentFunctions.error_log_print_r
        }
    }

    public static function getGlobalSettings($settingsKey = null)
    {
        $defaults = [
            'payments'       => [
                'currency'  => 'USD',
                'is_active' => 'no'
            ],
            'emailing'       => [
                'from_name'                  => '',
                'from_email'                 => '',
                'reply_to_name'              => '',
                'reply_to_email'             => '',
                'use_host_name'              => '',
                'use_host_email_on_reply'    => '',
                'attach_ics_on_confirmation' => '',
                'email_footer'               => ''
            ],
            'administration' => [
                'admin_email'            => '{{wp.admin_email}}',
                'summary_notification'   => 'no',
                'notification_frequency' => 'daily',
                'notification_day'       => 'mon',
                'start_day'              => 'sun',
                'auto_cancel_timing'     => '10',
                'auto_complete_timing'   => '60',
                'default_country'        => ''
            ],
            'time_format'    => '12',
            'theme'          => 'system-default'
        ];

        $settings = get_option('_fluent_booking_settings', []);

        if (empty($settings)) {
            $settings = [];
        }

        $settings['payments'] = CurrenciesHelper::getGlobalCurrencySettings();

        $settings = wp_parse_args($settings, $defaults);

        $emailSettings = $settings['emailing'];

        if (empty($settings['administration']['auto_cancel_timing'])) {
            $settings['administration']['auto_cancel_timing'] = '10';
        }

        if (empty($settings['administration']['auto_complete_timing'])) {
            $settings['administration']['auto_complete_timing'] = '10';
        }

        if (empty($emailSettings['from_name']) && defined('FLUENTCRM')) {
            $crmSettings = fluentcrmGetGlobalSettings('email_settings', []);
            $emailSettings['from_name'] = Arr::get($crmSettings, 'from_name');
            if (empty($emailSettings['from_email'])) {
                $emailSettings['from_email'] = Arr::get($crmSettings, 'from_email');
            }
            if (empty($emailSettings['reply_to_name'])) {
                $emailSettings['reply_to_name'] = Arr::get($crmSettings, 'reply_to_name');
            }
            if (empty($emailSettings['reply_to_email'])) {
                $emailSettings['reply_to_email'] = Arr::get($crmSettings, 'reply_to_email');
            }

            $settings['emailing'] = $emailSettings;
        }

        if ($settingsKey) {
            return Arr::get($settings, $settingsKey, []);
        }

        return $settings;

    }

    public static function getGlobalAdminSetting($key = null, $default = null)
    {
        static $settings;
        if ($settings) {

            if ($key) {
                return Arr::get($settings, $key, $default);
            }

            return $settings;
        }

        $globalSettings = self::getGlobalSettings();
        $settings = Arr::get($globalSettings, 'administration', []);

        if ($key) {
            return Arr::get($settings, $key, $default);
        }

        return $settings;
    }

    public static function getDefaultTimeFormat()
    {
        static $format;

        if ($format) {
            return $format;
        }

        $settings = self::getGlobalSettings();
        $format = Arr::get($settings, 'time_format', '24');
        return $format;
    }

    public static function getDefaultBookingFilters()
    {
        return apply_filters('fluent_booking/default_booking_filters', [
            'period' => 'upcoming',
            'author' => 'me', // me, all, calendar_id
            'event' => 'all',
            'event_type' => 'all'
        ]);
    }

    public static function getDefaultPaginations()
    {
        return apply_filters('fluent_booking/default_paginations', [
            'bookings'  => 10,
            'calendars' => 10,
            'coupons'   => 10,
            'availabilities' => 10
        ]);
    }

    public static function getVerifiedSenders()
    {
        $verifiedSenders = [];
        if (defined('FLUENTMAIL')) {
            $smtpSettings = get_option('fluentmail-settings', []);
            if ($smtpSettings && count($smtpSettings['mappings'])) {
                $verifiedSenders = array_keys($smtpSettings['mappings']);
            }
        }
        /**
         * Filter the verified email senders
         * @param array $verifiedSenders
         */
        return apply_filters('fluent_booking/verfied_email_senders', $verifiedSenders);
    }

    public static function getBookingReceiptLandingBaseUrl()
    {
        return apply_filters('fluent_booking/booking_receipt_landing_base_url', site_url('/'));
    }

    public static function getGlobalModuleSettings($cached = true)
    {
        static $settings = null;

        if ($cached && $settings !== null) {
            return $settings;
        }

        $settings = get_option('_fluent_booking_enabled_modules', []);

        if (empty($settings) || !\is_array($settings)) {
            $settings = [];
        }

        return $settings;
    }

    public static function updateGlobalModuleSettings($settings = [])
    {
        if (!is_array($settings)) {
            $settings = [];
        }

        update_option('_fluent_booking_enabled_modules', $settings);

        return self::getGlobalModuleSettings(false);
    }

    public static function isModuleEnabled($module)
    {
        $settings = self::getGlobalModuleSettings();

        return isset($settings[$module]) && $settings[$module] === 'yes';
    }

    /**
     * @return mixed|void
     */
    public static function fluentbooking_is_rtl()
    {
        /**
         * If FluentBooking is running on RTL Mode
         *
         * @param bool $is_rtl
         */
        return apply_filters('fluent_booking/is_rtl', is_rtl());
    }

    public static function fluentBookingUserAvatar($id_or_email, $args)
    {
        if (empty($id_or_email)) {
            return '';
        }
        return apply_filters('fluent_booking/author_photo', get_avatar_url($id_or_email), $args);
    }

    public static function getPrefSettings($cached = true)
    {
        static $pref = null;

        if ($cached && $pref) {
            return $pref;
        }

        $settings = [
            'frontend' => [
                'enabled'     => 'no',
                'slug'        => 'my-bookings',
                'render_type' => 'standalone',
                'page_id'     => ''
            ],
            'coupon' => [
                'enabled'     => 'no'
            ]
        ];

        $storedSettings = get_option('fluent_booking_modules', []);

        if ($storedSettings && is_array($storedSettings)) {
            $settings = wp_parse_args($storedSettings, $settings);
        } else {
            update_option('fluent_booking_modules', $settings, 'yes');
        }

        $pref = $settings;

        return $settings;
    }

    public static function getPrefSettins($cached = true)
    {
        return self::getPrefSettings($cached);
    }

    public static function getFeatures()
    {
        return apply_filters('fluent_booking/get_features', [
            'has_fluentcrm'    => defined('FLUENTCRM'),
            'has_fluentsmtp'   => defined('FLUENTMAIL'),
            'has_fluentform'   => defined('FLUENTFORM'),
            'has_fluentboards' => defined('FLUENT_BOARDS'),
            'has_fluentcart'   => defined('FLUENTCART_VERSION')
        ]);
    }

    public static function getActiveThemeName()
    {
        $ins = get_option('_fb_ins_by');

        if ($ins) {
            return sanitize_text_field($ins);
        }

        return get_option('template');
    }

    /**
     * Per-IP fixed-window rate limiter for public AJAX/REST endpoints.
     *
     * @param string $action Action name (e.g. apply_coupon, schedule_meeting).
     * @param int    $limit  Max requests per window.
     * @param int    $window Window in seconds.
     * @return bool True if under the limit (and the count was incremented),
     *              false if over.
     */
    public static function checkRateLimit($action, $limit, $window = 60)
    {
        $args = apply_filters('fluent_booking/public_ajax_ratelimit', [
            'limit'  => $limit,
            'window' => $window,
        ], $action);

        $limit  = max(1, (int) (isset($args['limit']) ? $args['limit'] : $limit));
        $window = max(1, (int) (isset($args['window']) ? $args['window'] : $window));

        $key   = 'fcal_ratelimit_' . $action . '_' . md5(self::getIp());
        $count = (int) get_transient($key);

        if ($count >= $limit) {
            return false;
        }

        set_transient($key, $count + 1, $window);

        return true;
    }
}
