<?php

namespace FluentCrm\App\Services;

use FluentCrm\App\Models\Lists;
use FluentCrm\App\Models\Subscriber;
use FluentCrm\App\Models\SubscriberPivot;
use FluentCrm\App\Models\SystemLog;
use FluentCrm\App\Models\Tag;
use FluentCrm\App\Models\UrlStores;
use FluentCrm\App\Models\Webhook;
use FluentCrm\App\Services\BlockRender\BlockEditorHelper;
use FluentCrm\Framework\Support\Arr;
use FluentCrm\Framework\Support\Str;

class Helper
{
    /**
     * Determine if the active Easy Digital Downloads version is supported.
     *
     * FluentCRM's EDD integration is EDD 3+ only because the current
     * integration depends on the EDD 3 order APIs and database tables.
     *
     * @return bool
     */
    public static function isEdd3()
    {
        return class_exists('\Easy_Digital_Downloads')
            && defined('EDD_VERSION')
            && version_compare(EDD_VERSION, '3.0', '>=');
    }

    /**
     * Parse mixed input into an array.
     *
     * Accepts either a native array or a JSON string. For string inputs,
     * it attempts decoding the raw payload first, then retries with
     * `wp_unslash()` only when the string changes. Returns `$default` when
     * decoding fails or when the decoded JSON is not an array.
     *
     * @param mixed $value Input value from request/body.
     * @param array $default Fallback value when parsing fails.
     * @return array
     */
    public static function parseArrayOrJson($value, $default = [])
    {
        if (!is_string($value)) {
            return is_array($value) ? $value : $default;
        }

        $payloads = [$value];
        $unslashed = wp_unslash($value);
        if ($unslashed !== $value) {
            $payloads[] = $unslashed;
        }

        foreach ($payloads as $payload) {
            $decoded = json_decode($payload, true);
            if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
                return $decoded;
            }
        }

        return $default;
    }

    public static function getLinksFromString($string)
    {
        preg_match_all('/<a[^>]+(href\=["|\'](http.*?)["|\'])/m', $string, $urls);

        if (!empty($urls[2])) {
            return $urls[2];
        }

        return [];
    }

    public static function urlReplaces($string)
    {
        preg_match_all('/<a[^>]+(href=["\'](http[^"\']*)["\'])/m', $string, $urls);
        $replaces = $urls[1];
        $urls = $urls[2];

        // Replace '|' with '%7C' in the URLs
        $urls = array_map(function ($url) {
            return str_replace('|', '%7C', $url);
        }, $urls);

        $formatted = [];
        $baseUrl = self::getSiteUrl();

        foreach ($urls as $index => $url) {
            $urlSlug = UrlStores::getUrlSlug($url);
            if (!$urlSlug) {
                continue;
            }
            $formatted[$replaces[$index]] = add_query_arg([
                'ns_url' => $urlSlug
            ], $baseUrl);
        }
        return $formatted;
    }

    public static function attachUrls($html, $campaignUrls, $insertId, $hash = false)
    {
        $hasSmartUrl = strpos($html, 'smart_url') !== false;

        foreach ($campaignUrls as $src => $url) {
            $url .= '&mid=' . $insertId;
            if ($hash) {
                $url .= '&fch=' . substr($hash, 0, 8);
            }

            if ($hasSmartUrl && strpos($src, 'smart_url') !== false) {
                $url .= '&signed_hash=' . rawurlencode(self::signSmartUrlHash($hash));
            }

            $campaignUrls[$src] = 'href="' . $url . '"';
        }
        return str_replace(array_keys($campaignUrls), array_values($campaignUrls), $html);
    }

    public static function attachAnonymousUrls($html, $campaignUrls, $insertId, $hash = false)
    {
        $hasSmartUrl = strpos($html, 'smart_url') !== false;
        foreach ($campaignUrls as $src => $url) {
            $url .= '&mid=' . $insertId . '&ano=1';
            if ($hash) {
                $url .= '&fch=' . substr($hash, 0, 8);
            }

            if ($hasSmartUrl && strpos($src, 'smart_url') !== false) {
                $url .= '&signed_hash=' . rawurlencode(self::signSmartUrlHash($hash));
            }

            $campaignUrls[$src] = 'href="' . $url . '"';
        }

        return str_replace(array_keys($campaignUrls), array_values($campaignUrls), $html);
    }

    /**
     * Generate an HMAC signature for smart URL verification.
     *
     * Uses a dedicated persistent key (not wp_salt) so that WordPress
     * salt rotation does not invalidate previously sent email links.
     *
     * @param string $hash The email hash to sign.
     * @return string
     */
    public static function signSmartUrlHash($hash)
    {
        return hash_hmac('sha256', $hash, wp_salt('auth'));
    }

    /**
     * Verify a smart URL signed hash.
     *
     * Supports both the new HMAC signatures and legacy bcrypt hashes
     * for backward compatibility with emails sent before the migration.
     *
     * @param string $emailHash The campaign email hash.
     * @param string $signedHash The signed hash from the URL.
     * @return bool
     */
    public static function verifySmartUrlHash($emailHash, $signedHash)
    {
        // New HMAC verification (fast, constant-time)
        $expected = self::signSmartUrlHash($emailHash);
        if (hash_equals($expected, $signedHash)) {
            return true;
        }

        // Backward compatibility: verify legacy bcrypt hashes
        // for emails sent before the HMAC migration
        return wp_check_password($emailHash, $signedHash);
    }

    public static function generateEmailHash($insertId = null)
    {
        return wp_generate_uuid4();
    }

    public static function injectTrackerPixel($emailBody, $hash, $emailId = null)
    {
        if (!$hash) {
            return $emailBody;
        }

        $trackingType = fluentcrmTrackEmailOpen();

        if (!$trackingType) {
            return $emailBody;
        }

        $args = [
            'fluentcrm' => 1,
            'route'     => 'open',
            '_e_hash'   => $hash,
            '_e_id'     => $emailId
        ];

        if ($trackingType === 'anonymous') {
            $args['ano'] = 1;
        }

        $trackImageUrl = add_query_arg($args, self::getSiteUrl());
        $trackPixelHtml = '<img src="' . esc_url($trackImageUrl) . '" alt="" width="1" height="1" border="0" style="display:block;width:1px;height:1px;border:0;outline:none;" />';

        if (strpos($emailBody, '{fluent_track_pixel}') !== false) {
            $emailBody = str_replace('{fluent_track_pixel}', $trackPixelHtml, $emailBody);
        } elseif (stripos($emailBody, '</body>') !== false) {
            // Case-insensitive replace before the first closing body tag.
            $emailBody = preg_replace('#</body>#i', $trackPixelHtml . '$0', $emailBody, 1);
        } else {
            // No body wrapper (e.g. raw_html templates with HTML fragments) —
            // append so the pixel is never silently dropped.
            $emailBody .= $trackPixelHtml;
        }

        return $emailBody;
    }

    public static function getProfileSections()
    {
        $sections = [
            'subscriber'        => [
                'name'    => 'subscriber',
                'title'   => __('Overview', 'fluent-crm'),
                'handler' => 'route'
            ],
            'subscriber_emails' => [
                'name'    => 'subscriber_emails',
                'title'   => __('Emails', 'fluent-crm'),
                'handler' => 'route'
            ],
        ];

        if (apply_filters('fluent_crm/sms_moudle_enabled', false)) {
            $sections['subscriber_sms'] = [
                'name'    => 'subscriber_sms',
                'title'   => __('SMS', 'fluent-crm'),
                'handler' => 'route'
            ];
        }

        if (self::getPurchaseHistoryProviders()) {
            $sections['subscriber_purchases'] = [
                'name'    => 'subscriber_purchases',
                'title'   => __('Purchases', 'fluent-crm'),
                'handler' => 'route'
            ];
        }

        if (defined('FLUENTFORM')) {
            $sections['subscriber_form_submissions'] = [
                'name'    => 'subscriber_form_submissions',
                'title'   => __('Forms', 'fluent-crm'),
                'handler' => 'route'
            ];
        }

        /**
         * Filter the list of support ticket providers.
         *
         * This filter allows you to modify the array of support ticket providers used in FluentCRM.
         *
         * @param array An array of support ticket providers.
         * @since 2.5.1
         *
         */
        $supportProviders = apply_filters('fluentcrm-support_tickets_providers', []);
        if ($supportProviders) {
            $sections['subscriber_support_tickets'] = [
                'name'    => 'subscriber_support_tickets',
                'title'   => __('Tickets', 'fluent-crm'),
                'handler' => 'route'
            ];
        }

        $sections['subscriber_notes'] = [
            'name'    => 'subscriber_notes',
            'title'   => __('Notes', 'fluent-crm'),
            'handler' => 'route'
        ];

        /**
         * Filter the contact profile sections in FluentCRM.
         *
         * This filter allows modification of the contact profile sections array in FluentCRM.
         *
         * @param array $sections An array of profile sections.
         * @since 2.2.0
         *
         */
        return apply_filters('fluentcrm_profile_sections', $sections);
    }

    public static function getDefaultEmailTemplate()
    {
        /**
         * Filter the default email design template.
         *
         * This filter allows you to modify the default email design template used by FluentCRM.
         *
         * @param string The default email design template. Default 'simple'.
         * @since 2.7.0
         *
         */
        return apply_filters('fluent_crm/default_email_design_template', 'simple');
    }

    public static function getGlobalSmartCodes()
    {
        $subscriberCodes = [
            'key'        => 'contact',
            'title'      => __('Contact', 'fluent-crm'),
            /**
             * Filter the smartcodes available for FluentCRM contacts.
             *
             * This filter allows modification of the smartcodes that can be used for FluentCRM contacts.
             *
             * @param array $smartcodes An associative array of smartcodes and their descriptions.
             *     Default smartcodes:
             *     - '{{contact.full_name}}'      => 'Full Name'
             *     - '{{contact.prefix}}'         => 'Name Prefix'
             *     - '{{contact.first_name}}'     => 'First Name'
             *     - '{{contact.last_name}}'      => 'Last Name'
             *     - '{{contact.email}}'          => 'Contact Email'
             *     - '{{contact.id}}'             => 'Contact ID'
             *     - '{{contact.user_id}}'        => 'User ID'
             *     - '{{contact.address_line_1}}' => 'Address Line 1'
             *     - '{{contact.address_line_2}}' => 'Address Line 2'
             *     - '{{contact.city}}'           => 'City'
             *     - '{{contact.state}}'          => 'State'
             *     - '{{contact.postal_code}}'    => 'Postal Code'
             *     - '{{contact.country}}'        => 'Country'
             *     - '{{contact.phone}}'          => 'Phone Number'
             *     - '{{contact.status}}'         => 'Status'
             *     - '{{contact.date_of_birth}}'  => 'Date of Birth'
             * @since 1.0.0
             *
             */
            'shortcodes' => apply_filters('fluentcrm_contact_smartcodes', [
                '{{contact.full_name}}'      => __('Full Name', 'fluent-crm'),
                '{{contact.prefix}}'         => __('Name Prefix', 'fluent-crm'),
                '{{contact.first_name}}'     => __('First Name', 'fluent-crm'),
                '{{contact.last_name}}'      => __('Last Name', 'fluent-crm'),
                '{{contact.email}}'          => __('Contact Email', 'fluent-crm'),
                '{{contact.id}}'             => __('Contact ID', 'fluent-crm'),
                '{{contact.user_id}}'        => __('User ID', 'fluent-crm'),
                '{{contact.address_line_1}}' => __('Address Line 1', 'fluent-crm'),
                '{{contact.address_line_2}}' => __('Address Line 2', 'fluent-crm'),
                '{{contact.city}}'           => __('City', 'fluent-crm'),
                '{{contact.state}}'          => __('State', 'fluent-crm'),
                '{{contact.postal_code}}'    => __('Postal Code', 'fluent-crm'),
                '{{contact.country}}'        => __('Country', 'fluent-crm'),
                '{{contact.phone}}'          => __('Phone Number', 'fluent-crm'),
                '{{contact.status}}'         => __('Status', 'fluent-crm'),
                '{{contact.date_of_birth}}'  => __('Date of Birth', 'fluent-crm')
            ])
        ];

        if (self::isCompanyEnabled()) {
            $subscriberCodes['shortcodes']['{{contact.company.name}}'] = __('Company Name', 'fluent-crm');
            $subscriberCodes['shortcodes']['{{contact.company.industry}}'] = __('Company Industry', 'fluent-crm');
            $subscriberCodes['shortcodes']['{{contact.company.address}}'] = __('Company Address', 'fluent-crm');
        }

        $smartCodes[] = $subscriberCodes;

        $customFields = fluentcrm_get_option('contact_custom_fields', []);

        if ($customFields) {
            $shortcodes = [];
            foreach ($customFields as $item) {
                $shortcodes['{{contact.custom.' . $item['slug'] . '}}'] = $item['label'];
            }
            $smartCodes[] = [
                'key'        => 'contact_custom_fields',
                'title'      => __('Custom Fields', 'fluent-crm'),
                'shortcodes' => $shortcodes
            ];
        }

        $smartCodes[] = [
            'key'        => 'general',
            'title'      => __('General', 'fluent-crm'),
            /**
             * Filter to modify the general smartcodes used in FluentCRM.
             *
             * @param array $shortcodes An associative array of smartcodes and their descriptions.
             *
             *        Default smartcodes:
             *        - '{{crm.business_name}}' => 'Business Name'
             *        - '{{crm.business_address}}' => 'Business Address'
             *        - '{{wp.admin_email}}' => 'Admin Email'
             *        - '##wp.url##' => 'Site URL'
             *        - '{{other.date.+2 days}}' => 'Dynamic Date (ex: +2 days from now)'
             *        - '{{other.date_format.D, d M, Y}}' => 'Custom Date Format (Any PHP Date Format)'
             *        - '{{other.latest_post.title}}' => 'Latest Post Title (Published)'
             *        - '##crm.unsubscribe_url##' => 'Unsubscribe URL'
             *        - '##crm.manage_subscription_url##' => 'Manage Subscription URL'
             *        - '##web_preview_url##' => 'View On Browser URL'
             *        - '{{crm.unsubscribe_html|Unsubscribe}}' => 'Unsubscribe Hyperlink HTML'
             *        - '{{crm.manage_subscription_html|Manage Preference}}' => 'Manage Subscription Hyperlink HTML'
             * @since 2.7.0
             *
             */
            'shortcodes' => apply_filters('fluent_crm/general_smartcodes', [
                '{{crm.business_name}}'                              => __('Business Name', 'fluent-crm'),
                '{{crm.business_address}}'                           => __('Business Address', 'fluent-crm'),
                '{{wp.admin_email}}'                                 => __('Admin Email', 'fluent-crm'),
                '##wp.url##'                                         => __('Site URL', 'fluent-crm'),
                '{{other.date.+2 days}}'                             => __('Dynamic Date (ex: +2 days from now)', 'fluent-crm'),
                '{{other.date_format.D, d M, Y}}'                    => __('Custom Date Format (Any PHP Date Format)', 'fluent-crm'),
                '{{other.latest_post.title}}'                        => __('Latest Post Title (Published)', 'fluent-crm'),
                '##crm.unsubscribe_url##'                            => __('Unsubscribe URL', 'fluent-crm'),
                '##crm.manage_subscription_url##'                    => __('Manage Subscription URL', 'fluent-crm'),
                '##web_preview_url##'                                => __('View On Browser URL', 'fluent-crm'),
                '{{crm.unsubscribe_html|Unsubscribe}}'               => __('Unsubscribe Hyperlink HTML', 'fluent-crm'),
                '{{crm.manage_subscription_html|Manage Preference}}' => __('Manage Subscription Hyperlink HTML', 'fluent-crm'),
            ])
        ];

        /**
         * Filter the smart code groups.
         *
         * This filter allows modification of the smart code groups array.
         *
         * @param array $smartCodes An array of smart code groups.
         * @since 2.7.0
         *
         */
        return apply_filters('fluent_crm/smartcode_groups', $smartCodes);
    }

    public static function getExtendedSmartCodes()
    {
        /**
         * Filter the extended smart codes for FluentCRM.
         *
         * This filter allows you to modify the array of extended smart codes used in FluentCRM.
         *
         * @param array An array of extended smart codes.
         * @since 2.7.0
         *
         */
        return array_values(apply_filters('fluent_crm/extended_smart_codes', []));
    }

    public static function getDoubleOptinSettings()
    {
        if ($settings = fluentcrm_get_option('double_optin_settings', [])) {
            if (empty($settings['after_confirmation_type'])) {
                $settings['after_confirmation_type'] = 'message';
                $settings['after_conf_redirect_url'] = '';
            }
            return $settings;
        }

        $businessName = '';
        $businessEmail = '';
        $businessAddress = '';
        $subject = 'Please Confirm Subscription';
        $business = fluentcrmGetGlobalSettings('business_settings', []);

        if (!empty($business['business_name'])) {
            $businessName = $business['business_name'];
            $subject = "{$businessName} : Please Confirm Subscription";
            if (!empty($business['business_address'])) {
                $businessAddress = $business['business_address'];
            }
        }

        $emailSettings = fluentcrmGetGlobalSettings('email_settings', []);
        if (!empty($emailSettings['from_email'])) {
            $businessEmail = $emailSettings['from_email'];
        }

        return [
            'email_subject'           => $subject,
            'email_pre_header'        => '',
            'design_template'         => 'simple',
            'email_body'              => '<h2>Please Confirm Subscription</h2><p><a style="color: #ffffff; background-color: #454545; font-size: 16px; border-radius: 5px; text-decoration: none; font-weight: normal; font-style: normal; padding: 0.8rem 1rem; border-color: #0072ff;" href="#activate_link#">Yes, subscribe me to the mailing list</a></p><p>&nbsp;</p><p>If you received this email by mistake, simply delete it. You won\'t be subscribed if you don\'t click the confirmation link above.</p><p>For questions about this list, please contact:<br />' . $businessEmail . '</p>',
            'after_confirmation_type' => 'message',
            'after_confirm_message'   => '<h2>Subscription Confirmed</h2><p>Your subscription to our list has been confirmed.</p><p>Thank you for subscribing!</p><p>&nbsp;</p><p>' . $businessName . '</p><p>' . $businessAddress . '</p><p>&nbsp;</p><p><a style="color: #ffffff; background-color: #404040; font-size: 16px; border-radius: 5px; text-decoration: none; font-weight: normal; font-style: normal; padding: 0.8rem 1rem; border-color: #0072ff;" href="' . site_url() . '">Continue to our Website</a></p>',
            'after_conf_redirect_url' => '',
        ];
    }

    public static function getEmailDesignTemplates()
    {
        $defaultDesignConfig = BlockEditorHelper::getDefaultPrefConfig();

        if (defined('FLUENTCAMPAIGN')) {
            $defaultDesignConfig['disable_footer'] = 'no';
        }

        $plainConfig = $defaultDesignConfig;
        $plainConfig['body_bg_color'] = '#FFFFFF';
        $plainConfig['design_template'] = 'plain';

        $classicConfig = $plainConfig;
        $classicConfig['design_template'] = 'classic';

        $emptyConfig = [
            'content_font_family' => "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'",
        ];

        /**
         * Filter the email design templates available in FluentCRM.
         *
         * @param array {
         *     An array of email design templates.
         *
         * @type array $simple {
         * @type string $id The template ID.
         * @type string $label The template label.
         * @type string $image The URL to the template image.
         * @type array $config The configuration array for the template.
         * @type bool $use_gutenberg Whether to use Gutenberg editor.
         *     }
         * @type array $plain {
         * @type string $id The template ID.
         * @type string $label The template label.
         * @type string $image The URL to the template image.
         * @type array $config The configuration array for the template.
         * @type bool $use_gutenberg Whether to use Gutenberg editor.
         *     }
         * @type array $classic {
         * @type string $id The template ID.
         * @type string $label The template label.
         * @type string $image The URL to the template image.
         * @type array $config The configuration array for the template.
         * @type bool $use_gutenberg Whether to use Gutenberg editor.
         *     }
         * @type array $raw_classic {
         * @type string $id The template ID.
         * @type string $label The template label.
         * @type string $image The URL to the template image.
         * @type array $config The configuration array for the template.
         * @type bool $use_gutenberg Whether to use Gutenberg editor.
         * @type string $template_type The type of the template.
         * @type string $template_info Additional information about the template.
         *     }
         * @type array $raw_html {
         * @type string $id The template ID.
         * @type string $label The template label.
         * @type string $image The URL to the template image.
         * @type array $config The configuration array for the template.
         * @type bool $use_gutenberg Whether to use Gutenberg editor.
         * @type string $template_type The type of the template.
         * @type string $template_info Additional information about the template.
         *     }
         * }
         * @since 2.6.51
         *
         */
        $templates = apply_filters('fluent_crm/email_design_templates', [
            'simple'      => [
                'id'            => 'simple',
                'label'         => __('Simple Boxed', 'fluent-crm'),
                'image'         => fluentCrmMix('images/gutenberg-builder.svg'),
                'config'        => $defaultDesignConfig,
                'use_gutenberg' => true
            ],
            'plain'       => [
                'id'            => 'plain',
                'label'         => __('Plain Centered', 'fluent-crm'),
                'image'         => fluentCrmMix('images/plain_centered.svg'),
                'config'        => $plainConfig,
                'use_gutenberg' => true
            ],
            'classic'     => [
                'id'            => 'classic',
                'label'         => __('Plain Left', 'fluent-crm'),
                'image'         => fluentCrmMix('images/plain_left.svg'),
                'config'        => $classicConfig,
                'use_gutenberg' => true
            ],
            'raw_classic' => [
                'id'            => 'raw_classic',
                'label'         => __('Classic Editor', 'fluent-crm'),
                'image'         => fluentCrmMix('images/classic-editor.svg'),
                'config'        => $emptyConfig,
                'use_gutenberg' => false,
                'template_type' => 'classic_editor',
                'template_info' => '<h3>Classic Text Based Email</h3><p>Type your simple email and FluentCRM will send that without altering any design processing. The default footer will be injected after your content if footer is not disabled.</p>'
            ],
            'raw_html'    => [
                'id'            => 'raw_html',
                'label'         => __('Raw HTML', 'fluent-crm'),
                'image'         => fluentCrmMix('images/html-editor.svg'),
                'config'        => [],
                'use_gutenberg' => false,
                'template_type' => 'raw_text_box',
                'template_info' => '<h3>Raw HTML Template</h3><p>You can use any type of valid html and FluentCRM will send that without altering any design processing.</p>'
            ]
        ]);

        if (!defined('FLUENTCAMPAIGN')) {
            $templates['visual_builder'] = [
                'id'            => 'visual_builder',
                'label'         => __('Visual Builder', 'fluent-crm'),
                'image'         => fluentCrmMix('images/visual-builder.svg'),
                'config'        => $emptyConfig,
                'use_gutenberg' => false,
                'template_type' => 'visual_builder_demo'
            ];
        }

        return $templates;
    }

    public static function getTemplateConfig($templateName = '', $withGlobal = true)
    {
        if (!$templateName) {
            $templateName = self::getDefaultEmailTemplate();
        }
        $templates = self::getEmailDesignTemplates();
        if (!isset($templates[$templateName])) {
            $templateName = 'simple';
        }

        $config = Arr::get($templates, $templateName . '.config', []);

        if ($withGlobal) {
            $globalSettings = fluentcrm_get_option('global_email_style_config', []);
            return wp_parse_args($globalSettings, $config);
        }

        return $config;

    }

    public static function getActivatedFeatures()
    {
        return [
            'fluentcampaign'       => defined('FLUENTCAMPAIGN_FRAMEWORK_VERSION'),
            'frontend_portal'      => defined('FLUENTCAMPAIGN_FRAMEWORK_VERSION') && self::isExperimentalEnabled('frontend_portal'),
            'company_module'       => self::isCompanyEnabled(),
            'event_tracking'       => self::isExperimentalEnabled('event_tracking'),
            /**
             * Filter to disable email open tracking in FluentCRM.
             *
             * This filter allows to disable email open tracking globally.
             *
             * @param bool  Whether to disable email open tracking. Default is false.
             * @return bool Filtered value to enable or disable email open tracking.
             * @since 2.8.0
             *
             */
            'email_open_tracking'  => !apply_filters('fluentcrm_disable_email_open_tracking', false),
            /**
             * Filter to enable or disable email click tracking.
             *
             * This filter allows you to control whether email click tracking is enabled or disabled.
             *
             * @param bool Whether to enable email click tracking. Default true.
             * @since 2.8.0
             *
             */
            'email_click_tracking' => apply_filters('fluent_crm/track_click', true),
        ];
    }

    public static function getContactPrefixes($withKeyed = false)
    {
        /**
         * Base contact prefixes with translatable labels.
         * These will show up in Loco Translate under the 'fluent-crm' domain.
         */
        $prefixes = [
            __('Mr', 'fluent-crm'),
            __('Mrs', 'fluent-crm'),
            __('Ms', 'fluent-crm')
        ];

        /**
         * Filter the contact name prefixes.
         *
         * This filter is deprecated. Please use fluent_crm/contact_name_prefixes instead.
         *
         * @param array An array of contact name prefixes.
         * @deprecated 2.7.0 Use fluent_crm/contact_name_prefixes instead.
         *
         * @since 2.5.5
         *
         */
        $prefixes = apply_filters('fluentcrm_contact_name_prefixes', $prefixes);

        /**
         * Filter the contact name prefixes.
         *
         * @param array $prefixes An array of contact name prefixes.
         * @since 2.7.0
         *
         */
        $prefixes = apply_filters('fluent_crm/contact_name_prefixes', $prefixes);

        if ($withKeyed) {
            $keyedNames = [];
            foreach ($prefixes as $prefix) {
                $keyedNames[$prefix] = $prefix;
            }
            return $keyedNames;
        }
        return $prefixes;
    }

    public static function getGlobalEmailSettings()
    {
        $defaultFooter = '{{crm.business_name}}, {{crm.business_address}}<br>Don\'t like these emails? <a href="##crm.unsubscribe_url##">Unsubscribe</a> or <a href="##crm.manage_subscription_url##">Manage Email Subscriptions</a>';

        $defaults = [
            'from_name'         => '',
            'from_email'        => '',
            'emails_per_second' => 15,
            'email_footer'      => $defaultFooter,
            'pref_list_type'    => 'no',
            'pref_list_items'   => [],
            'pref_form'         => 'no',
            'pref_general'      => ['first_name', 'last_name'],
            'pref_custom'       => [],
            'show_on_page'      => 'no',
            'pref_page_id'      => ''
        ];

        if ($settings = fluentcrmGetGlobalSettings('email_settings', [])) {
            if (empty($settings['email_footer'])) {
                $settings['email_footer'] = $defaultFooter;
            }

            if (empty($settings['pref_form'])) {
                $settings['pref_form'] = 'no';
                $settings['pref_general'] = ['first_name', 'last_name'];
                $settings['pref_custom'] = [];
            }

            if (!isset($settings['pref_general'])) {
                $settings['pref_general'] = [];
            }

            if (!isset($settings['pref_custom'])) {
                $settings['pref_custom'] = [];
            }

            return wp_parse_args($settings, $defaults);
        }

        return $defaults;
    }

    public static function getPurchaseHistoryProviders()
    {
        $validProviders = [];

        if (defined('FLUENTCART_VERSION')) {
            $validProviders['fluent_cart'] = [
                'title' => __('FluentCart Purchase History', 'fluent-crm'),
                'name'  => __('FluentCart', 'fluent-crm')
            ];
        }

        if (defined('WC_PLUGIN_FILE')) {
            $validProviders['woocommerce'] = [
                'title' => __('Woocommerce Purchase History', 'fluent-crm'),
                'name'  => __('WooCommerce', 'fluent-crm')
            ];
        }

        if (self::isEdd3()) {
            $validProviders['edd'] = [
                'title' => __('EDD Purchase History', 'fluent-crm'),
                'name'  => __('Easy Digital Downloads', 'fluent-crm')
            ];
        }

        if (defined('WPPAYFORM_VERSION')) {
            $validProviders['payform'] = [
                'title' => __('Paymattic Purchase History', 'fluent-crm'),
                'name'  => __('Paymattic', 'fluent-crm')
            ];
        }

        if (defined('PMPRO_VERSION') && defined('FLUENTCAMPAIGN')) {
            $validProviders['pmpro'] = [
                'title' => __('Paid Membership Pro Purchase History', 'fluent-crm'),
                'name'  => __('Paid Membership Pro', 'fluent-crm')
            ];
        }

        /**
         * Filter the list of valid purchase history providers.
         *
         * This filter allows modification of the valid purchase history providers used in FluentCRM.
         *
         * @param array $validProviders An array of valid purchase history providers.
         * @since 2.7.0
         *
         */
        return apply_filters('fluent_crm/purchase_history_providers', $validProviders);
    }

    public static function getThemePrefScheme()
    {
        static $pref;
        if (!$pref) {

            $color_palette = [
                [
                    "name"  => __("Black", "fluent-crm"),
                    "slug"  => "black",
                    "color" => "#000000"
                ],
                [
                    "name"  => __("Cyan bluish gray", "fluent-crm"),
                    "slug"  => "cyan-bluish-gray",
                    "color" => "#abb8c3"
                ],
                [
                    "name"  => __("White", "fluent-crm"),
                    "slug"  => "white",
                    "color" => "#ffffff"
                ],
                [
                    "name"  => __("Pale pink", "fluent-crm"),
                    "slug"  => "pale-pink",
                    "color" => "#f78da7"
                ],
                [
                    "name"  => __("Luminous vivid orange", "fluent-crm"),
                    "slug"  => "luminous-vivid-orange",
                    "color" => "#ff6900"
                ],
                [
                    "name"  => __("Luminous vivid amber", "fluent-crm"),
                    "slug"  => "luminous-vivid-amber",
                    "color" => "#fcb900"
                ],
                [
                    "name"  => __("Light green cyan", "fluent-crm"),
                    "slug"  => "light-green-cyan",
                    "color" => "#7bdcb5"
                ],
                [
                    "name"  => __("Vivid green cyan", "fluent-crm"),
                    "slug"  => "vivid-green-cyan",
                    "color" => "#00d084"
                ],
                [
                    "name"  => __("Pale cyan blue", "fluent-crm"),
                    "slug"  => "pale-cyan-blue",
                    "color" => "#8ed1fc"
                ],
                [
                    "name"  => __("Vivid cyan blue", "fluent-crm"),
                    "slug"  => "vivid-cyan-blue",
                    "color" => "#0693e3"
                ],
                [
                    "name"  => __("Vivid purple", "fluent-crm"),
                    "slug"  => "vivid-purple",
                    "color" => "#9b51e0"
                ]
            ];

            $font_sizes = [
                [
                    'name'      => __('Small', 'fluent-crm'),
                    'shortName' => 'S',
                    'size'      => 14,
                    'slug'      => 'small'
                ],
                [
                    'name'      => __('Medium', 'fluent-crm'),
                    'shortName' => 'M',
                    'size'      => 18,
                    'slug'      => 'medium'
                ],
                [
                    'name'      => __('Large', 'fluent-crm'),
                    'shortName' => 'L',
                    'size'      => 24,
                    'slug'      => 'large'
                ],
                [
                    'name'      => __('Larger', 'fluent-crm'),
                    'shortName' => 'XL',
                    'size'      => 32,
                    'slug'      => 'larger'
                ]
            ];

            /**
             * Filter the theme preferences for FluentCRM.
             *
             * This filter allows modification of the theme preferences, including colors and font sizes.
             *
             * @param array {
             *     The theme preferences.
             *
             * @type array $colors The color palette.
             * @type array $font_sizes The font sizes.
             * }
             * @since 2.6.51
             *
             */
            $pref = apply_filters('fluent_crm/theme_pref', [
                'colors'     => (array)$color_palette,
                'font_sizes' => (array)$font_sizes
            ]);
        }

        return $pref;

    }

    public static function funnelLabelColors()
    {
        $colors = [
            '#D6D8FF',
            '#D4ECD6',
            '#FEE8B5',
            '#D7E8EF',
            '#FFCACA',
            '#F8D7C4',
            '#D4D7DC',
            '#FFD9E3'
        ];

        /**
         * Filter the funnel label colors.
         *
         * This filter allows modification of the funnel label colors.
         *
         * @param array $colors An array of colors for the funnel labels.
         * @since 2.9.30
         *
         */
        return apply_filters('fluent_crm/funnel_label_color', $colors);
    }

    public static function getColorSchemeValue($colorName)
    {
        static $colorMap = [];
        if (isset($colorMap[$colorName])) {
            return $colorMap[$colorName];
        }
        $pref = self::getThemePrefScheme();
        $colors = $pref['colors'];
        foreach ($colors as $color) {
            $colorMap[$color['slug']] = $color['color'];
            if ($color['slug'] == $colorName) {
                return $color['color'];
            }
        }

        $color_palette = self::getThemeColorPalette();
        return self::getColorBySlug($color_palette, $colorName);
    }

    public static function getColorBySlug($color_palette, $slug)
    {
        if (!$color_palette || !is_array($color_palette)) {
            return null;
        }

        foreach ($color_palette as $color) {
            if (isset($color['slug']) && isset($color['color']) && $color['slug'] === $slug) {
                return $color['color'];
            }
        }

        return null;
    }

    public static function getThemeColorPalette()
    {
        $color_palette = current((array)get_theme_support('editor-color-palette'));
        $theme_json_path = get_theme_file_path('theme.json');

        if (file_exists($theme_json_path)) {
            $theme_json = json_decode(file_get_contents($theme_json_path), true);

            if (isset($theme_json['settings']['color']['palette'])) {
                $color_palette = $theme_json['settings']['color']['palette'];
            }
        }
        if (!$color_palette) {
            $color_palette = [];
        }

        return (array)$color_palette;
    }

    public static function getThemeFontSizes()
    {
        $font_sizes = current((array)get_theme_support('editor-font-sizes'));
        $theme_json_path = get_theme_file_path('theme.json');

        if (file_exists($theme_json_path)) {
            $theme_json = json_decode(file_get_contents($theme_json_path), true);

            if (isset($theme_json['settings']['typography']['fontSizes'])) {
                $font_sizes = $theme_json['settings']['typography']['fontSizes'];
            }
        }

        return $font_sizes;
    }


    public static function generateThemePrefCss()
    {
        static $color_css;
        if ($color_css) {
            return $color_css;
        }
        $pref = self::getThemePrefScheme();

        $css = '';
        if (isset($pref['colors'])) {
            foreach ($pref['colors'] as $color) {
                if (isset($color['slug']) && isset($color['color'])) {
                    $slug = self::kebabCase($color['slug']);
                    $css .= '.has-' . $slug . '-color  { color: ' . $color['color'] . ';} ';
                    $css .= '.has-' . $slug . '-background-color  { background-color: ' . $color['color'] . '; background: ' . $color['color'] . '; } ';
                    $css .= 'a.has-' . $slug . '-background-color  { border: 1px solid ' . $color['color'] . '; } ';
                }
            }
        }

        if (isset($pref['font_sizes'])) {
            foreach ($pref['font_sizes'] as $size) {
                if (isset($size['slug']) && isset($size['size'])) {
                    $slug = self::kebabCase($size['slug']);
                    $css .= '.fc_email_body .has-' . $slug . '-font-size  { font-size: ' . $size['size'] . 'px !important;} ';
                }
            }
        }

        // Generate CSS for theme color palette
        $themeColors = self::getThemeColorPalette();
        if (!empty($themeColors)) {
            foreach ($themeColors as $themeColor) {
                $color = $themeColor['color'];

                // Converts 'palette1' to 'palette-1'
                $slug = self::normalizeColorSlug($themeColor['slug']);

                // Stores the original slug value without modification
                $originalSlug = $themeColor['slug'];

                $css .= ".fc_email_body .has-{$originalSlug}-background-color { background-color: {$color};}";
                $css .= ".fc_email_body .has-{$originalSlug}-color { color: {$color};}";
                $css .= ".fc_email_body .has-{$slug}-background-color { background-color: {$color};}";
                $css .= ".fc_email_body .has-{$slug}-color { color: {$color};}";
            }
        }

        // Generate CSS for theme font sizes
        $themeFontSizes = self::getThemeFontSizes();
        if (!empty($themeFontSizes)) {
            foreach ($themeFontSizes as $themeFontSize) {
                $size = $themeFontSize['size'];
                $slug = $themeFontSize['slug'];
                $css .= ".fc_email_body .has-{$slug}-font-size { font-size: {$size} !important;}";
            }
        }

        $color_css = $css;
        return $color_css;
    }

    private static function normalizeColorSlug($slug)
    {
        // Normalize the slug
        $slug = strtolower($slug);

        // If the slug already follows "text-number" format, return it as is
        if (preg_match('/^(.*?)-(\d+)$/', $slug, $matches)) {
            return $slug;
        }

        // Otherwise, fix cases like "theme-palette1" -> "theme-palette-1"
        $parts = preg_split('/(\d+)/', $slug, -1, PREG_SPLIT_DELIM_CAPTURE);

        if (count($parts) > 1 && ctype_digit(trim($parts[count($parts) - 2]))) {
            return implode('-', array_filter($parts));
        }

        return $slug;
    }

    public static function kebabCase($string)
    {
        return implode('-', array_filter(preg_split('/(\d)/', strtolower(strval($string)), -1, PREG_SPLIT_DELIM_CAPTURE)));
    }

    public static function getMailHeadersFromSettings($emailSettings = [])
    {
        if (empty($emailSettings) || Arr::get($emailSettings, 'is_custom') == 'no') {
            $emailSettings = fluentcrmGetGlobalSettings('email_settings', []);
        }

        if (empty($emailSettings)) {
            return [];
        }

        $headers = [];
        if (Arr::get($emailSettings, 'from_name') && Arr::get($emailSettings, 'from_email')) {
            $headers['From'] = $emailSettings['from_name'] . ' <' . $emailSettings['from_email'] . '>';
        } else if ($fromEmail = Arr::get($emailSettings, 'from_email')) {
            $headers['From'] = $fromEmail;
        }

        if (Arr::get($emailSettings, 'reply_to_name') && Arr::get($emailSettings, 'reply_to_email')) {
            $headers['Reply-To'] = $emailSettings['reply_to_name'] . ' <' . $emailSettings['reply_to_email'] . '>';
        } else if ($replyTo = Arr::get($emailSettings, 'reply_to_email')) {
            $headers['Reply-To'] = $replyTo;
        }

        return $headers;
    }

    public static function getMailHeader($existingHeader = [])
    {
        if (!empty($existingHeader['From'])) {
            return $existingHeader;
        }

        if (!empty($existingHeader['Reply-To'])) {
            return $existingHeader;
        }

        $headers = [];
        static $globalHeaders;
        if ($globalHeaders) {
            return $globalHeaders;
        }

        $globalEmailSettings = fluentcrmGetGlobalSettings('email_settings', []);

        $fromName = Arr::get($globalEmailSettings, 'from_name');
        $fromEmail = Arr::get($globalEmailSettings, 'from_email');

        if ($fromName && $fromEmail) {
            $headers['From'] = $fromName . ' <' . $fromEmail . '>';
        } else if ($fromEmail) {
            $headers['From'] = $fromEmail;
        }

        $replyName = Arr::get($globalEmailSettings, 'reply_to_name');
        $replyEmail = Arr::get($globalEmailSettings, 'reply_to_email');

        if ($replyName && $replyEmail) {
            $headers['Reply-To'] = $replyName . ' <' . $replyEmail . '>';
        } else if ($replyEmail) {
            $headers['Reply-To'] = $replyEmail;
        }

        $globalHeaders = $headers;

        return $globalHeaders;
    }

    public static function recordCampaignRevenue($campaignId, $amount, $orderId, $currency = 'USD', $isRefunded = false)
    {
        $currency = strtolower($currency);
        $existing = fluentcrm_get_campaign_meta($campaignId, '_campaign_revenue');
        $data = ['orderIds' => []];

        if ($existing && isset($existing->value['orderIds']) && $existing->value['orderIds']) {
            $data['orderIds'] = $existing->value['orderIds'];
            $data[$currency] = $existing->value[$currency];
        } else {
            $data[$currency] = 0;
        }
        if (!in_array($orderId, $data['orderIds'])) {
            $data['orderIds'][] = $orderId;
        }

        if ($isRefunded) {
            if ($data[$currency] > $amount) {
                $data[$currency] -= $amount;
                $key = array_search($orderId, $data['orderIds']);
                if ($key !== false) {
                    unset($data['orderIds'][$key]);
                    $data['orderIds'] = array_values($data['orderIds']);
                }
            }
        } else {
            if ($existing && isset($existing->value['orderIds']) && in_array($orderId, $existing->value['orderIds'])) {
                $data[$currency] = $existing->value[$currency];
            } else {
                $data[$currency] += $amount;
            }
        }

        return fluentcrm_update_campaign_meta($campaignId, '_campaign_revenue', $data);
    }

    public static function getWPMapUserInfo($user)
    {
        if (is_numeric($user)) {
            $user = get_user_by('ID', $user);
        }

        if (!$user) {
            return [];
        }

        $subscriber = array_filter([
            'user_id'    => $user->ID,
            'first_name' => $user->first_name,
            'last_name'  => $user->last_name,
            'email'      => $user->user_email
        ]);

        if ($address1 = get_user_meta($user->ID, 'billing_address_1', true)) {
            $subscriber['address_line_1'] = $address1;
        }

        if ($address2 = get_user_meta($user->ID, 'billing_address_2', true)) {
            $subscriber['address_line_2'] = $address2;
        }

        if ($city = get_user_meta($user->ID, 'billing_city', true)) {
            $subscriber['city'] = $city;
        }

        if ($postalCode = get_user_meta($user->ID, 'billing_postcode', true)) {
            $subscriber['postal_code'] = $postalCode;
        }

        if ($country = get_user_meta($user->ID, 'billing_country', true)) {
            $subscriber['country'] = $country;
        }

        if ($state = get_user_meta($user->ID, 'billing_state', true)) {
            $subscriber['state'] = $state;
        }

        if ($phone = get_user_meta($user->ID, 'billing_phone', true)) {
            $subscriber['phone'] = $phone;
        }

        /**
         * Filter the subscriber data before it is processed.
         *
         * This filter allows you to modify the subscriber data before it is processed.
         *
         * @param array $subscriber The subscriber data.
         * @param object $user The WordPress user object.
         * @since 2.5.3
         *
         */
        $subscriber = apply_filters('fluentcrm_user_map_data', $subscriber, $user);

        $fillables = (new Subscriber)->getFillable();

        $subscriber = Arr::only($subscriber, $fillables);

        return array_filter($subscriber);
    }

    public static function isUserSyncEnabled()
    {
        static $result = null;
        if ($result === null) {
            $settings = fluentcrm_get_option('user_syncing_settings', []);
            $result = $settings && isset($settings['status']) && $settings['status'] == 'yes';
        }

        return $result;
    }

    public static function isContactDeleteOnUserDeleteEnabled()
    {
        static $result = null;
        if ($result === null) {
            $settings = fluentcrm_get_option('user_syncing_settings', []);
            $result = $settings && isset($settings['delete_contact_on_user_delete']) && $settings['delete_contact_on_user_delete'] == 'yes';
        }

        return $result;
    }

    public static function deleteContacts($contactIds)
    {
        if (!$contactIds) {
            return false;
        }
        if (!is_array($contactIds)) {
            $contactIds = (array)$contactIds;
        }

        do_action('fluentcrm_before_subscribers_deleted', $contactIds);
        Subscriber::whereIn('id', $contactIds)->delete();
        do_action('fluentcrm_after_subscribers_deleted', $contactIds);
        return true;
    }

    public static function sendDoubleOptin($contactIds)
    {
        if (!$contactIds) {
            return false;
        }
        if (!is_array($contactIds)) {
            $contactIds = (array)$contactIds;
        }

        $subscribers = Subscriber::whereIn('id', $contactIds)->where('status', 'pending')->get();
        foreach ($subscribers as $subscriber) {
            $subscriber->sendDoubleOptinEmail();
        }
        return true;
    }

    public static function hasComplianceText($text)
    {
        /**
         * Filters the compliance check string result.
         *
         * This filter allows you to modify the result of the compliance check string.
         *
         * @param mixed $result The result of the compliance check string.
         * @param string $text The text being checked for compliance.
         * @since 2.8.33
         *
         */
        $result = apply_filters('fluent_crm/disable_check_compliance_string', false, $text);

        if ($result) {
            return true; // directly return true if the filter returns true, would be better if we could return the $result of the filter
        }

        return (bool)preg_match('/##crm\.manage_subscription_url##|##crm\.unsubscribe_url##|\{\{crm\.unsubscribe_html|\{\{crm\.manage_subscription_html|\{\{crm_global_email_footer\}\}/', $text);
    }

    public static function maybeDisableEmojiOnEmail()
    {
        static $disabled;
        if ($disabled) {
            return;
        }
        /**
         * Filter to disable emoji conversion to images in FluentCRM.
         *
         * This filter allows you to disable the conversion of emojis to images.
         * By default, this filter is set to true, meaning the conversion is enabled.
         * You can use this filter to return false if you want to disable the conversion.
         *
         * @param bool Whether to disable emoji conversion to images. Default true.
         * @since 2.7.0
         *
         */
        if (apply_filters('fluent_crm/disable_emoji_to_image', true)) {
            remove_filter('wp_mail', 'wp_staticize_emoji_for_email');
        }
        $disabled = true;
    }

    public static function getPublicLists()
    {
        $emailSettings = self::getGlobalEmailSettings();
        $lists = [];
        $preListType = Arr::get($emailSettings, 'pref_list_type', 'none');
        if ($preListType == 'filtered_only') {
            $prefListItems = Arr::get($emailSettings, 'pref_list_items', []);
            if ($prefListItems) {
                $lists = Lists::whereIn('id', $prefListItems)->get();
                if ($lists->isEmpty()) {
                    return [];
                }
            }
        } else if ($preListType == 'all') {
            $lists = Lists::get();
            if ($lists->isEmpty()) {
                return [];
            }
        }

        return $lists;
    }

    public static function getAdvancedFilterOptions()
    {
        $groups = [
            'subscriber' => [
                'label'    => __('Contact', 'fluent-crm'),
                'value'    => 'subscriber',
                'children' => [
                    [
                        'label' => __('General Properties', 'fluent-crm'),
                        'value' => 'search',
                    ],
                    [
                        'label' => __('First Name', 'fluent-crm'),
                        'value' => 'first_name',
                        'type'  => 'nullable_text',
                    ],
                    [
                        'label' => __('Last Name', 'fluent-crm'),
                        'value' => 'last_name',
                        'type'  => 'nullable_text',
                    ],
                    [
                        'label' => __('Email', 'fluent-crm'),
                        'value' => 'email',
                    ],
                    [
                        'label' => __('Address Line 1', 'fluent-crm'),
                        'value' => 'address_line_1',
                        'type'  => 'nullable_text',
                    ],
                    [
                        'label' => __('Address Line 2', 'fluent-crm'),
                        'value' => 'address_line_2',
                        'type'  => 'nullable_text',
                    ],
                    [
                        'label' => __('City', 'fluent-crm'),
                        'value' => 'city',
                        'type'  => 'nullable_text',
                    ],
                    [
                        'label' => __('State', 'fluent-crm'),
                        'value' => 'state',
                        'type'  => 'nullable_text',
                    ],
                    [
                        'label' => __('Postal Code', 'fluent-crm'),
                        'value' => 'postal_code',
                        'type'  => 'nullable_text',
                    ],
                    [
                        'label'             => __('Country', 'fluent-crm'),
                        'value'             => 'country',
                        'type'              => 'selections',
                        'component'         => 'options_selector',
                        'option_key'        => 'countries',
                        'is_multiple'       => true,
                        'is_singular_value' => true
                    ],
                    [
                        'label' => __('Phone', 'fluent-crm'),
                        'value' => 'phone',
                        'type'  => 'nullable_text',
                    ],
                    [
                        'label' => __('WP User ID', 'fluent-crm'),
                        'value' => 'user_id',
                        'type'  => 'numeric',
                    ],
                    [
                        'label'       => __('Name Prefix (Title)', 'fluent-crm'),
                        'value'       => 'prefix',
                        'type'        => 'selections',
                        'options'     => self::getContactPrefixes(true),
                        'is_multiple' => true,
                        'is_only_in'  => true
                    ],
                    [
                        'label' => __('Source', 'fluent-crm'),
                        'value' => 'source'
                    ],
                    [
                        'label' => __('Date of Birth', 'fluent-crm'),
                        'value' => 'date_of_birth',
                        'type'  => 'dates',
                    ],
                    [
                        'label' => __('Last Activity', 'fluent-crm'),
                        'value' => 'last_activity',
                        'type'  => 'dates',
                    ],
                    [
                        'label' => __('Created At', 'fluent-crm'),
                        'value' => 'created_at',
                        'type'  => 'dates',
                    ],

                ],
            ],
            'segment'    => [
                'label'    => __('Contact Segment', 'fluent-crm'),
                'value'    => 'segment',
                'children' => [
                    [
                        'label'             => __('Status', 'fluent-crm'),
                        'value'             => 'status',
                        'type'              => 'selections',
                        'component'         => 'options_selector',
                        'option_key'        => 'statuses',
                        'is_multiple'       => true,
                        'is_singular_value' => true
                    ],
                    [
                        'label'             => __('Type', 'fluent-crm'),
                        'value'             => 'contact_type',
                        'type'              => 'selections',
                        'component'         => 'options_selector',
                        'option_key'        => 'contact_types',
                        'is_multiple'       => false,
                        'is_singular_value' => true
                    ],
                    [
                        'label'       => __('Tags', 'fluent-crm'),
                        'value'       => 'tags',
                        'type'        => 'selections',
                        'component'   => 'options_selector',
                        'option_key'  => 'tags',
                        'is_multiple' => true,
                    ],
                    [
                        'label'       => __('Lists', 'fluent-crm'),
                        'value'       => 'lists',
                        'type'        => 'selections',
                        'component'   => 'options_selector',
                        'option_key'  => 'lists',
                        'is_multiple' => true,
                    ],
                    [
                        'label'             => __('WP User Role', 'fluent-crm'),
                        'value'             => 'user_role',
                        'type'              => 'selections',
                        'component'         => 'options_selector',
                        'option_key'        => 'user_roles_options',
                        'is_multiple'       => false,
                        'is_singular_value' => true,
                        'help'              => __('Filter by user role, please make sure your users are synced with your FluentCRM contacts', 'fluent-crm')
                    ],
                ],
            ],
            'activities' => [
                'label'    => __('Contact Activities', 'fluent-crm'),
                'value'    => 'activities',
                'children' => [
                    [
                        'label' => __('Last Email Sent', 'fluent-crm'),
                        'value' => 'email_sent',
                        'type'  => 'dates',
                    ],
                    [
                        'label' => __('Last Email Open', 'fluent-crm'),
                        'value' => 'email_opened',
                        'type'  => 'dates',
                        'help'  => __('Please note that, some email clients send false-positive for email open pixel tracking so it may not 100% correct.', 'fluent-crm')
                    ],
                    [
                        'label' => __('Last Email Clicked', 'fluent-crm'),
                        'value' => 'email_link_clicked',
                        'type'  => 'dates',
                    ],
                    [
                        'label'              => __('Campaign Email -', 'fluent-crm'),
                        'value'              => 'campaign_email_activity',
                        'type'               => 'selections',
                        'component'          => 'ajax_selector',
                        'option_key'         => 'campaigns',
                        'is_multiple'        => false,
                        'custom_operators'   => [
                            'clicked'     => 'link clicked',
                            'not_clicked' => 'did not click',
                            'open'        => 'opened',
                            'no_open'     => 'did not open yet',
                            'in'          => 'in (email sent)',
                            'not_in'      => 'not in (regardless of status)'
                        ],
                        'experimental_cache' => true,
                        'help'               => __('This will get only the contacts who got email in the selected campaign and then filter by email open/link clicked or not. <br />Please note that, some email clients send false-positive for email open pixel tracking so it may not 100% correct.', 'fluent-crm')
                    ],
                    [
                        'label'              => __('Automation Activity -', 'fluent-crm'),
                        'value'              => 'automation_activity',
                        'type'               => 'selections',
                        'component'          => 'ajax_selector',
                        'option_key'         => 'funnels',
                        'is_multiple'        => false,
                        'custom_operators'   => [
                            'completed' => 'status completed',
                            'active'    => 'status active',
                            'cancelled' => 'status cancelled',
                            'waiting'   => 'status waiting',
                            'in'        => 'in (regardless of status)',
                            'not_in'    => 'not in (regardless of status)'
                        ],
                        'experimental_cache' => true,
                        'help'               => __('You can filter your contacts based on activity in a specific automation funnel.', 'fluent-crm')
                    ],
                    [
                        'label'              => __('Email Sequence Activity -', 'fluent-crm'),
                        'value'              => 'email_sequence_activity',
                        'type'               => 'selections',
                        'component'          => 'ajax_selector',
                        'option_key'         => 'email_sequences',
                        'is_multiple'        => false,
                        'custom_operators'   => [
                            'completed' => 'status completed',
                            'active'    => 'status active',
                            'cancelled' => 'status cancelled',
                            'in'        => 'in (regardless of status)',
                            'not_in'    => 'not in (regardless of status)'
                        ],
                        'experimental_cache' => true,
                        'help'               => __('You can filter your contacts based on activity in a specific email sequences.', 'fluent-crm')
                    ]
                ]
            ]
        ];

        if (self::isCompanyEnabled()) {
            $groups['segment']['children'][] = [
                'label'              => __('Company', 'fluent-crm'),
                'value'              => 'companies',
                'type'               => 'selections',
                'component'          => 'ajax_selector',
                'option_key'         => 'companies',
                'is_multiple'        => true,
                'is_singular_value'  => true,
                'experimental_cache' => true
            ];
            $groups['segment']['children'][] = [
                'label'              => __('Company - Industry', 'fluent-crm'),
                'value'              => 'company_industry',
                'type'               => 'selections',
                'component'          => 'ajax_selector',
                'option_key'         => 'company_industries',
                'is_multiple'        => true,
                'is_singular_value'  => true,
                'experimental_cache' => true
            ];
            $groups['segment']['children'][] = [
                'label'              => __('Company - Type', 'fluent-crm'),
                'value'              => 'company_type',
                'type'               => 'selections',
                'component'          => 'ajax_selector',
                'option_key'         => 'company_types',
                'is_multiple'        => true,
                'is_singular_value'  => true,
                'experimental_cache' => true
            ];
        }

        if ($customFields = fluentcrm_get_custom_contact_fields()) {
            // form data for custom fields in groups
            $children = [];
            foreach ($customFields as $field) {
                $item = [
                    'label' => $field['label'],
                    'value' => $field['slug'],
                    'type'  => $field['type'],
                ];

                if ($item['type'] == 'number') {
                    $item['type'] = 'numeric';
                } else if ($item['type'] == 'date') {
                    $item['type'] = 'dates';
                    $item['date_type'] = 'date';
                    $item['value_format'] = 'YYYY-MM-DD';
                } else if ($item['type'] == 'date_time') {
                    $item['type'] = 'dates';
                    $item['has_time'] = 'yes';
                    $item['date_type'] = 'datetime';
                    $item['value_format'] = 'YYYY-MM-DD HH:mm:ss';
                } else if (isset($field['options'])) {
                    $item['type'] = 'selections';
                    $options = $field['options'];
                    $formattedOptions = [];
                    foreach ($options as $option) {
                        $formattedOptions[$option] = $option;
                    }
                    $item['options'] = $formattedOptions;
                    $isMultiple = in_array($field['type'], ['checkbox', 'select-multi']);
                    $item['is_multiple'] = $isMultiple;
                    if ($isMultiple) {
                        $item['is_singular_value'] = true;
                    }

                } else {
                    $item['type'] = 'text';
                }

                $children[] = $item;

            }

            $groups['custom_fields'] = [
                'label'    => __('Custom Fields', 'fluent-crm'),
                'value'    => 'custom_fields',
                'children' => $children
            ];
        }

        if (!defined('FLUENTCAMPAIGN')) {
            $disabled = true;
            if (defined('WC_PLUGIN_FILE')) {
                $groups['woo'] = [
                    'label'    => __('WooCommerce', 'fluent-crm'),
                    'value'    => 'woo',
                    'children' => [
                        [
                            'value'    => 'total_order_count',
                            'label'    => __('Total Order Count (Pro Required)', 'fluent-crm'),
                            'type'     => 'numeric',
                            'disabled' => true
                        ],
                        [
                            'value'    => 'total_order_value',
                            'label'    => __('Total Order value (Pro Required)', 'fluent-crm'),
                            'type'     => 'numeric',
                            'disabled' => true
                        ],
                        [
                            'value'    => 'last_order_date',
                            'label'    => __('Last Order Date (Pro Required)', 'fluent-crm'),
                            'type'     => 'dates',
                            'disabled' => true
                        ],
                        [
                            'value'    => 'first_order_date',
                            'label'    => __('First Order Date (Pro Required)', 'fluent-crm'),
                            'type'     => 'dates',
                            'disabled' => true
                        ],
                        [
                            'value'       => 'purchased_items',
                            'label'       => __('Purchased Products (Pro Required)', 'fluent-crm'),
                            'type'        => 'selections',
                            'component'   => 'product_selector',
                            'is_multiple' => true,
                            'disabled'    => true
                        ],
                        [
                            'value'             => 'commerce_exist',
                            'label'             => __('Is a customer? (Pro Required)', 'fluent-crm'),
                            'type'              => 'selections',
                            'is_multiple'       => false,
                            'disable_values'    => true,
                            'value_description' => __('This filter will check if a contact has at least one shop order or not', 'fluent-crm'),
                            'custom_operators'  => [
                                'exist'     => 'Yes',
                                'not_exist' => 'No',
                            ],
                            'disabled'          => true
                        ]
                    ],
                ];
            }

            if (self::isEdd3()) {
                $groups['edd'] = [
                    'label'    => __('EDD', 'fluent-crm'),
                    'value'    => 'edd',
                    'children' => [
                        [
                            'value'    => 'total_order_count',
                            'label'    => __('Total Order Count (Pro Required)', 'fluent-crm'),
                            'type'     => 'numeric',
                            'disabled' => true
                        ],
                        [
                            'value'    => 'total_order_value',
                            'label'    => __('Total Order Value (Pro Required)', 'fluent-crm'),
                            'type'     => 'numeric',
                            'disabled' => true
                        ],
                        [
                            'value'    => 'last_order_date',
                            'label'    => __('Last Order Date (Pro Required)', 'fluent-crm'),
                            'type'     => 'dates',
                            'disabled' => true
                        ],
                        [
                            'value'    => 'first_order_date',
                            'label'    => __('First Order Date (Pro Required)', 'fluent-crm'),
                            'type'     => 'dates',
                            'disabled' => true
                        ],
                        [
                            'value'       => 'purchased_items',
                            'label'       => __('Purchased Products (Pro Required)', 'fluent-crm'),
                            'type'        => 'selections',
                            'component'   => 'product_selector',
                            'is_multiple' => true,
                            'disabled'    => true
                        ],
                    ],
                ];
            }

            if (class_exists('\Affiliate_WP')) {
                $groups['aff_wp'] = [
                    'label'    => 'AffiliateWP',
                    'value'    => 'aff_wp',
                    'children' => [
                        [
                            'value'    => 'is_affiliate',
                            'label'    => __('Is Affiliate (Pro Required)', 'fluent-crm'),
                            'type'     => 'single_assert_option',
                            'options'  => [
                                'yes' => __('Yes', 'fluent-crm'),
                                'no'  => __('No', 'fluent-crm')
                            ],
                            'disabled' => $disabled
                        ],
                        [
                            'value'    => 'affiliate_id',
                            'label'    => __('Affiliate ID (Pro Required)', 'fluent-crm'),
                            'type'     => 'numeric',
                            'disabled' => $disabled
                        ],
                        [
                            'value'    => 'referrals',
                            'label'    => __('Total Referrals (Pro Required)', 'fluent-crm'),
                            'type'     => 'numeric',
                            'disabled' => $disabled
                        ],
                        [
                            'value'    => 'status',
                            'label'    => __('Status (Pro Required)', 'fluent-crm'),
                            'type'     => 'single_assert_option',
                            'options'  => [
                                'active'   => __('Active', 'fluent-crm'),
                                'inactive' => __('Inactive', 'fluent-crm'),
                                'pending'  => __('Pending', 'fluent-crm')
                            ],
                            'disabled' => $disabled
                        ],
                        [
                            'value'    => 'earnings',
                            'label'    => __('Earnings (Pro Required)', 'fluent-crm'),
                            'type'     => 'numeric',
                            'disabled' => $disabled
                        ],
                        [
                            'value'    => 'unpaid_earnings',
                            'label'    => __('Unpaid Earnings (Pro Required)', 'fluent-crm'),
                            'type'     => 'numeric',
                            'disabled' => $disabled
                        ],
                        [
                            'value'    => 'date_registered',
                            'label'    => __('Registration Date (Pro Required)', 'fluent-crm'),
                            'type'     => 'dates',
                            'disabled' => $disabled
                        ],
                        [
                            'value'    => 'last_payment_date',
                            'label'    => __('Last Payout Date (Pro Required)', 'fluent-crm'),
                            'type'     => 'dates',
                            'disabled' => $disabled
                        ]
                    ]
                ];
            }

            if (defined('LEARNDASH_VERSION')) {
                $groups['learndash'] = [
                    'label'    => __('LearnDash', 'fluent-crm'),
                    'value'    => 'learndash',
                    'children' => [
                        [
                            'value'    => 'last_order_date',
                            'label'    => __('Last Enrollment Date (Pro Required)', 'fluent-crm'),
                            'type'     => 'dates',
                            'disabled' => $disabled
                        ],
                        [
                            'value'    => 'first_order_date',
                            'label'    => __('First Enrollment Date (Pro Required)', 'fluent-crm'),
                            'type'     => 'dates',
                            'disabled' => $disabled
                        ],
                        [
                            'value'       => 'purchased_items',
                            'label'       => __('Enrollment Courses (Pro Required)', 'fluent-crm'),
                            'type'        => 'selections',
                            'component'   => 'product_selector',
                            'is_multiple' => true,
                            'disabled'    => $disabled
                        ],
                        [
                            'value'        => 'purchased_groups',
                            'label'        => __('Enrollment Groups (Pro Required)', 'fluent-crm'),
                            'type'         => 'selections',
                            'component'    => 'product_selector',
                            'is_multiple'  => true,
                            'extended_key' => 'groups',
                            'disabled'     => $disabled,
                            'options'      => []
                        ],
                        [
                            'value'       => 'purchased_categories',
                            'label'       => __('Enrollment Categories (Pro Required)', 'fluent-crm'),
                            'type'        => 'selections',
                            'component'   => 'tax_selector',
                            'taxonomy'    => 'ld_course_category',
                            'is_multiple' => true,
                            'disabled'    => $disabled
                        ],
                        [
                            'value'       => 'purchased_tags',
                            'label'       => __('Enrollment Tags (Pro Required)', 'fluent-crm'),
                            'type'        => 'selections',
                            'component'   => 'tax_selector',
                            'taxonomy'    => 'ld_course_tag',
                            'is_multiple' => true,
                            'disabled'    => $disabled
                        ]
                    ]
                ];
            }

            if (defined('LLMS_PLUGIN_FILE')) {
                $groups['lifterlms'] = [
                    'label'    => __('LifterLMS', 'fluent-crm'),
                    'value'    => 'lifterlms',
                    'children' => [
                        [
                            'value'    => 'last_order_date',
                            'label'    => __('Last Enrollment Date (Pro Required)', 'fluent-crm'),
                            'type'     => 'dates',
                            'disabled' => $disabled
                        ],
                        [
                            'value'    => 'first_order_date',
                            'label'    => __('First Enrollment Date (Pro Required)', 'fluent-crm'),
                            'type'     => 'dates',
                            'disabled' => $disabled
                        ],
                        [
                            'value'       => 'purchased_items',
                            'label'       => __('Enrollment Courses (Pro Required)', 'fluent-crm'),
                            'type'        => 'selections',
                            'component'   => 'product_selector',
                            'is_multiple' => true,
                            'disabled'    => $disabled
                        ],
                        [
                            'value'        => 'purchased_groups',
                            'label'        => __('Enrollment Memberships (Pro Required)', 'fluent-crm'),
                            'type'         => 'selections',
                            'component'    => 'product_selector',
                            'extended_key' => 'groups',
                            'is_multiple'  => true,
                            'disabled'     => $disabled
                        ],
                        [
                            'value'       => 'purchased_categories',
                            'label'       => __('Enrollment Categories (Pro Required)', 'fluent-crm'),
                            'type'        => 'selections',
                            'component'   => 'tax_selector',
                            'taxonomy'    => 'course_cat',
                            'is_multiple' => true,
                            'disabled'    => $disabled
                        ],
                        [
                            'value'       => 'purchased_tags',
                            'label'       => __('Enrollment Tags (Pro Required)', 'fluent-crm'),
                            'type'        => 'selections',
                            'component'   => 'tax_selector',
                            'taxonomy'    => 'course_tag',
                            'is_multiple' => true,
                            'disabled'    => $disabled
                        ]
                    ],
                ];
            }
        }

        /**
         * Filter the advanced filter options for FluentCRM.
         *
         * This filter allows modification of the advanced filter options used in FluentCRM.
         *
         * @param array $groups The current filter options.
         * @since 2.5.1
         *
         */
        $groups = apply_filters('fluentcrm_advanced_filter_options', $groups);

        return array_values($groups);
    }

    public static function getComplianceSettings()
    {
        $defaults = [
            'anonymize_ip'           => 'no',
            'delete_contact_on_user' => 'no',
            'personal_data_export'   => 'yes',
            'one_click_unsubscribe'  => 'no',
            'enable_gravatar'        => 'yes',
            'gravatar_fallback'      => 'yes',
            'email_click_tracking'   => 'yes', // 'no'|'yes'|'anonymous'
            'email_open_tracking'    => 'yes', // 'no'|'yes'|'anonymous'
        ];

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

        return wp_parse_args($settings, $defaults);
    }

    public static function getSiteUrl($path = '', $scheme = null)
    {
        return site_url($path, $scheme);
    }

    public static function isExperimentalEnabled($module)
    {
        $settings = self::getExperimentalSettings();
        return Arr::get($settings, $module) === 'yes';
    }

    public static function getExperimentalSettings()
    {
        static $settings;
        if ($settings) {
            return $settings;
        }

        $defaults = [
            'campaign_archive'        => 'no',
            'campaign_group_by_month' => 'no',
            'campaign_search'         => '',
            'campaign_max_number'     => 50,
            'campaign_ids'            => [],
            'campaign_status'         => 'archived',
            'frontend_portal'         => 'no',
            'frontend_portal_slug'    => 'fluentcrm',
            'frontend_portal_render_type' => 'standalone',
            'frontend_portal_page_id' => '',
            'classic_date_time'       => 'no',
            'company_module'          => 'no',
            'company_auto_logo'       => 'no',
            'disable_visual_ai'       => 'no',
            'multi_threading_emails'  => 'no',
            'system_logs'             => 'no',
            'event_tracking'          => 'no',
            'abandoned_cart'          => 'no',
            'activity_log'            => 'no',
            'sms_module'              => 'no',
        ];

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

        if (!$settings || !is_array($settings)) {
            $settings = $defaults;
            return $settings;
        }

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

        return $settings;
    }

    public static function willMultiThreadEmail($minPendingLimit = 300)
    {
        if (!self::isExperimentalEnabled('multi_threading_emails')) {
            return false;
        }

        $rowcount = self::getUpcomingEmailCount();

        return $rowcount >= $minPendingLimit;
    }

    public static function getUpcomingEmailCount()
    {
        global $wpdb;
        // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
        return $wpdb->get_var("SELECT count(*) as aggregate FROM `{$wpdb->prefix}fc_campaign_emails` WHERE `status` IN ('pending', 'scheduled') AND `scheduled_at` <= '" . current_time('mysql') . "'");
    }

    public static function sanitizeHtml($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'           => [],
        ];

        //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);
        }

        /**
         * Filter the allowed HTML tags.
         *
         * This filter allows modification of the HTML tags that are allowed.
         *
         * @param array $tags An array of allowed HTML tags.
         * @since 2.7.0
         *
         */
        $tags = apply_filters('fluent_crm/allowed_html_tags', $tags);

        return wp_kses($html, $tags);
    }

    public static function hasConditionOnString($string)
    {
        return (bool)preg_match('/conditional-group|fcrmConditionType|conditional-content|fc-cond-blocks|fc_vis_cond/', $string);
    }

    public static function getEmailFooterContent($campaign = null)
    {
        if ($campaign && isset($campaign->settings)) {

            if (Arr::get($campaign->settings, 'is_transactional') == 'yes') {
                return '';
            }

            $customFooter = Arr::get($campaign->settings, 'footer_settings.custom_footer');
            $emailFooter = Arr::get($campaign->settings, 'footer_settings.footer_content');

            if ($customFooter === 'yes' && $emailFooter) {
                return $emailFooter;
            }
        }

        return Arr::get(self::getGlobalEmailSettings(), 'email_footer', '');
    }

    public static function getFooterConfig($campaign = null)
    {

        $defaults = [
            'disable_footer' => 'no',
            'custom_footer'  => 'no',
            'footer_content' => '',
            'font_size'      => 13,
            'font_color'     => '#202020',
            'background_color' => 'transparent',
            'footer_padding' => 20
        ];

        if ($campaign && isset($campaign->settings)) {
            if (Arr::get($campaign->settings, 'is_transactional') == 'yes') {
                return [];
            }
            $footerSettings = Arr::get($campaign->settings, 'footer_settings', []);
            $disableFooter = Arr::get($footerSettings, 'disable_footer');
            if ($disableFooter !== 'yes' && $disableFooter !== 'no') {
                $disableFooter = Arr::get($campaign->settings, 'template_config.disable_footer');
            }

            if ($disableFooter == 'yes') {
                $defaults['disable_footer'] = 'yes';
                $defaults['footer_content'] = '';
                return $defaults;
            }
            if (!empty($footerSettings['font_size'])) {
                $defaults['font_size'] = $footerSettings['font_size'];
            }

            if (!empty($footerSettings['font_color'])) {
                $defaults['font_color'] = $footerSettings['font_color'];
            }

            if (!empty($footerSettings['background_color'])) {
                $defaults['background_color'] = $footerSettings['background_color'];
            }

            $footerPadding = Arr::get($footerSettings, 'footer_padding');
            if ($footerPadding !== null && $footerPadding !== '') {
                $defaults['footer_padding'] = min(80, max(0, intval($footerPadding)));
            } else {
                $defaults['footer_padding'] = 20;
            }

            $customFooter = Arr::get($campaign->settings, 'footer_settings.custom_footer');
            $emailFooter = Arr::get($campaign->settings, 'footer_settings.footer_content');

            if ($customFooter === 'yes' && $emailFooter) {
                $defaults['footer_content'] = $emailFooter;
                return $defaults;
            }
        }

        $globalContent = Arr::get(self::getGlobalEmailSettings(), 'email_footer', '');

        $defaults['footer_content'] = $globalContent;

        return $defaults;
    }

    public static function isCompanyEnabled()
    {
        return self::isExperimentalEnabled('company_module');
    }

    public static function companyCategories()
    {
        /**
         * Filter the list of company categories.
         *
         * This filter allows modification of the company categories list.
         *
         * @param array An array of company categories.
         * @since 2.8.0
         *
         */
        return apply_filters('fluent_crm/company_categories', [
            'Accounting',
            'Airlines/Aviation',
            'Alternative Dispute Resolution',
            'Alternative Medicine',
            'Animation',
            'Apparel & Fashion',
            'Architecture & Planning',
            'Arts and Crafts',
            'Automotive',
            'Aviation & Aerospace',
            'Banking',
            'Biotechnology',
            'Broadcast Media',
            'Building Materials',
            'Business Supplies and Equipment',
            'Capital Markets',
            'Chemicals',
            'Civic & Social Organization',
            'Civil Engineering',
            'Commercial Real Estate',
            'Computer & Network Security',
            'Computer Games',
            'Computer Hardware',
            'Computer Networking',
            'Computer Software',
            'Internet',
            'Construction',
            'Consumer Electronics',
            'Consumer Goods',
            'Consumer Services',
            'Cosmetics',
            'Dairy',
            'Defense & Space',
            'Design',
            'Education Management',
            'E-Learning',
            'Electrical/Electronic Manufacturing',
            'Entertainment',
            'Environmental Services',
            'Events Services',
            'Executive Office',
            'Facilities Services',
            'Farming',
            'Financial Services',
            'Fine Art',
            'Fishery',
            'Food & Beverages',
            'Food Production',
            'Fund-Raising',
            'Furniture',
            'Gambling & Casinos',
            'Glass, Ceramics & Concrete',
            'Government Administration',
            'Government Relations',
            'Graphic Design',
            'Health, Wellness and Fitness',
            'Higher Education',
            'Hospital & Health Care',
            'Hospitality',
            'Human Resources',
            'Import and Export',
            'Individual & Family Services',
            'Industrial Automation',
            'Information Services',
            'Information Technology and Services',
            'Insurance',
            'International Affairs',
            'International Trade and Development',
            'Investment Banking',
            'Investment Management',
            'Judiciary',
            'Law Enforcement',
            'Law Practice',
            'Legal Services',
            'Legislative Office',
            'Leisure, Travel & Tourism',
            'Libraries',
            'Logistics and Supply Chain',
            'Luxury Goods & Jewelry',
            'Machinery',
            'Management Consulting',
            'Maritime',
            'Market Research',
            'Marketing and Advertising',
            'Mechanical or Industrial Engineering',
            'Media Production',
            'Medical Devices',
            'Medical Practice',
            'Mental Health Care',
            'Military',
            'Mining & Metals',
            'Motion Pictures and Film',
            'Museums and Institutions',
            'Music',
            'Nanotechnology',
            'Newspapers',
            'Non-Profit Organization Management',
            'Oil & Energy',
            'Online Media',
            'Outsourcing/Offshoring',
            'Package/Freight Delivery',
            'Packaging and Containers',
            'Paper & Forest Products',
            'Performing Arts',
            'Pharmaceuticals',
            'Philanthropy',
            'Photography',
            'Plastics',
            'Political Organization',
            'Primary/Secondary Education',
            'Printing',
            'Professional Training & Coaching',
            'Program Development',
            'Public Policy',
            'Public Relations and Communications',
            'Public Safety',
            'Publishing',
            'Railroad Manufacture',
            'Ranching',
            'Real Estate',
            'Recreational Facilities and Services',
            'Religious Institutions',
            'Renewables & Environment',
            'Research',
            'Restaurants',
            'Retail',
            'Security and Investigations',
            'Semiconductors',
            'Shipbuilding',
            'Sporting Goods',
            'Sports',
            'Staffing and Recruiting',
            'Supermarkets',
            'Telecommunications',
            'Textiles',
            'Think Tanks',
            'Tobacco',
            'Translation and Localization',
            'Transportation/Trucking/Railroad',
            'Utilities',
            'Venture Capital & Private Equity',
            'Veterinary',
            'Warehousing',
            'Wholesale',
            'Wine and Spirits',
            'Wireless',
            'Writing and Editing'
        ]);
    }

    public static function companyTypes()
    {
        /**
         * Filter the list of company types.
         *
         * This filter allows modification of the company types array.
         *
         * @param array An array of company types.
         * @since 2.8.0
         *
         */
        return apply_filters('fluent_crm/company_types', [
            'Prospect',
            'Partner',
            'Reseller',
            'Vendor',
            'Other'
        ]);
    }

    public static function getCompanyProfileSections()
    {
        $sections = [
            'overview'   => [
                'name'    => 'view_company',
                'title'   => __('Contacts', 'fluent-crm'),
                'handler' => 'route'
            ],
            'activities' => [
                'name'    => 'company_activities',
                'title'   => __('Notes & Activities', 'fluent-crm'),
                'handler' => 'route'
            ],
        ];

        /**
         * Filter the company profile sections.
         *
         * This filter allows modification of the company profile sections.
         *
         * @param array The array of company profile sections.
         * @since 2.8.0
         *
         */
        return apply_filters('fluent_crm/company_profile_sections', $sections);
    }

    public static function maybeParseAndFilterWebhookData(Webhook $webhook, $postData, $key)
    {
        $data = Arr::get($webhook->value, $key, []);
        if (!empty($postData[$key])) {
            $postedData = Arr::get($postData, $key, []);

            if (is_string($postedData)) {
                $postedData = explode(',', $postedData);
                $postedData = map_deep($postedData, 'intval');
            }

            $newData = [];
            foreach ($postedData as $item) {
                if (is_numeric($item)) {
                    $newData[] = $item;
                }
            }

            if (!empty($newData)) {
                $data = $newData;
            }

            $data = array_filter($data);
        }

        return $data;
    }

    public static function getNoteSyncFields()
    {
        $fields = array(
            'type'        => array(
                'type'    => 'input-option',
                'label'   => __('Type', 'fluent-crm'),
                'id'      => 'fc_note_type',
                'name'    => 'type',
                'options' => fluentcrm_activity_types()
            ),
            'created_at'  => array(
                'type'         => 'input-date',
                'data_type'    => 'datetime',
                'name'         => 'created_at',
                'label'        => __('Date Time', 'fluent-crm'),
                'id'           => 'fc_note_title',
                'value_format' => 'YYYY-MM-DD HH:mm:ss',
                'help'         => __('keep blank for current time', 'fluent-crm')
            ),
            'title'       => array(
                'type'        => 'input-text',
                'name'        => 'title',
                'label'       => __('Title', 'fluent-crm'),
                'id'          => 'fc_note_title',
                'placeholder' => __('Your Note Title', 'fluent-crm')
            ),
            'description' => array(
                'type'  => 'wp-editor',
                'name'  => 'description',
                'label' => __('Description', 'fluent-crm'),
                'id'    => 'fc_note_desc'
            ),
        );

        /**
         * Filter the contact note fields.
         *
         * This filter allows modification of the contact note fields.
         *
         * @param array $fields The contact note fields.
         * @since 2.8.40
         *
         */
        return apply_filters('fluent_crm/contact_note_fields', $fields);
    }

    public static function debugLog($title, $description = '', $type = 'info')
    {
        static $isEnabled = null;

        if ($isEnabled === null) {
            $isEnabled = (defined('FLUENT_CRM_DEBUG_LOG') && FLUENT_CRM_DEBUG_LOG) || self::isExperimentalEnabled('system_logs');
        }

        if (!$isEnabled) {
            return null;
        }

        if (!is_string($description)) {
            $description = json_encode($description);
        }

        return SystemLog::create([
            'title'       => sanitize_text_field($title),
            'description' => wp_kses_post($description)
        ]);
    }

    public static function getNextMinuteTaskTimeStamp()
    {
        $lastRunAt = fluentCrmGetOptionCache('_fcrm_last_scheduler');

        if ($lastRunAt) {
            $nextRun = $lastRunAt + 60;
        } else {
            $nextRun = as_next_scheduled_action('fluentcrm_scheduled_every_minute_tasks');
        }

        if ($nextRun === true || !$nextRun) {
            $nextRun = time() + 60;
        }

        return $nextRun;
    }

    public static function isWooHposEnabled()
    {
        static $enabled = null;
        if ($enabled !== null) {
            return $enabled;
        }

        $enabled = class_exists('\Automattic\WooCommerce\Utilities\OrderUtil') && \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled();

        return $enabled;
    }

    public static function searchWPUsers($searchQuery, $limit = 20)
    {
        $search = sanitize_text_field($searchQuery);

        // Search by user login, email, and nicename
        $args = array(
            'role__not_in' => array('Administrator'),
            'search'       => '*' . $search . '*',
            'number'       => $limit
        );

        // Get users by login, email, and nicename
        $user_query = new \WP_User_Query($args);
        $users_by_login = $user_query->get_results();
        $users = array_unique($users_by_login, SORT_REGULAR);

        return $users;
    }

    public static function latestListIdOfSubscriber($contactId)
    {
        $listId = SubscriberPivot::where('subscriber_id', $contactId)
            ->where('object_type', 'FluentCrm\App\Models\Lists')
            ->orderBy('created_at', 'DESC')
            ->orderBy('id', 'DESC')
            ->value('object_id');

        return $listId;
    }

    public static function createNewTags($tagsArray)
    {
        $tags = [];
        foreach ($tagsArray as $tag) {
            $tag = sanitize_text_field($tag);
            //if that tag already exists then I need only it's id
            $sameTag = Tag::where('title', $tag)->first();
            if ($sameTag) {
                $tags[] = $sameTag->id;
                continue;
            }

            $tagModel = Helper::createTag($tag);

            if ($tagModel) {
                $tags[] = $tagModel->id;
            }
        }

        return $tags;
    }

    public static function createNewLists($listsArray)
    {
        $lists = [];
        foreach ($listsArray as $list) {
            $list = sanitize_text_field($list);
            //if that list already exists then I need only it's id
            $sameList = Lists::where('title', $list)->first();
            if ($sameList) {
                $lists[] = $sameList->id;
                continue;
            }

            $listModel = Helper::createList($list);

            if ($listModel) {
                $lists[] = $listModel->id;
            }
        }

        return $lists;
    }

    public static function getNewAttachableLists($listsArray, $currentListIds, $ListsForAllContacts)
    {
        $listIds = [];

        foreach ($listsArray as $listTitle) {
            $listTitle = sanitize_text_field($listTitle);

            $existinglist = Lists::where('title', $listTitle)->first();
            if ($existinglist) {
                if (!in_array($existinglist->id, $currentListIds) && !in_array($existinglist->id, $ListsForAllContacts)) {
                    //if that existing list is not already in user's list and not in those lists that will be applied to all subscribers
                    $listIds[] = $existinglist->id;
                }
            } else {
                $newList = Helper::createList($listTitle);
                $listIds[] = $newList->id;
            }
        }

        return $listIds;
    }

    public static function getNewAttachableTags($tagsArray, $currentTagIds, $TagsForAllContacts)
    {
        $tagIds = [];

        foreach ($tagsArray as $tagTitle) {
            $tagTitle = sanitize_text_field($tagTitle);

            $existingTag = Tag::where('title', $tagTitle)->first();
            if ($existingTag) {
                if (!in_array($existingTag->id, $currentTagIds) && !in_array($existingTag->id, $TagsForAllContacts)) {
                    //if that existing tag is not already in user's tag and not in those tags that will be applied to all subscribers
                    $tagIds[] = $existingTag->id;
                }
            } else {
                $newList = Helper::createTag($tagTitle);
                $tagIds[] = $newList->id;
            }
        }

        return $tagIds;
    }

    private static function createList($listTitle)
    {
        $baseSlug = Str::slug($listTitle);
        $slug = $baseSlug;
        $counter = 1;

        // Ensure unique slug
        while (Lists::where('slug', $slug)->exists()) {
            $slug = "{$baseSlug}-{$counter}";
            $counter++;
        }

        return Lists::create(
            [
                'title' => $listTitle,
                'slug'  => $slug
            ]
        );
    }

    private static function createTag($tagTitle)
    {
        $baseSlug = Str::slug($tagTitle);
        $slug = $baseSlug;
        $counter = 1;

        // Ensure unique slug
        while (Tag::where('slug', $slug)->exists()) {
            $slug = "{$baseSlug}-{$counter}";
            $counter++;
        }

        return Tag::create(
            [
                'title' => $tagTitle,
                'slug'  => $slug
            ]
        );
    }

    /**
     * Converts text into a URL-friendly slug, handling Latin and non-Latin scripts.
     *
     * @param string $text Input text to slugify
     * @param string $fallback Fallback slug if input is empty or invalid
     * @return string Sanitized slug
     */
    public static function slugify($text, $fallback = '')
    {
        // Normalize input: cast to string and trim whitespace
        $text = trim((string)$text);

        // Handle empty input
        if (empty($text)) {
            return sanitize_title($fallback ?: self::generateUniqueId(), $fallback);
        }

        // Process as Latin-based text
        $slug = remove_accents($text); // Convert accents (e.g., é → e)
        $slug = strtolower($slug); // Convert to lowercase
        $slug = preg_replace('/[^a-z0-9\-_]/', '-', $slug); // Replace non-alphanumeric with dashes
        $slug = preg_replace('/[\-_]{2,}/', '-', $slug); // Collapse multiple dashes/underscores
        $slug = trim($slug, '-_'); // Trim leading/trailing dashes/underscores

        // Check for empty result or non-Latin scripts
        if (empty($slug) || preg_match('/[^\p{Latin}\p{N}\-_ ]/u', $text)) {
            $slug = self::generateUniqueId();
        }

        // Final cleanup with WordPress sanitize_title
        return sanitize_title($slug, $fallback);
    }

    /**
     * Generates a unique, hyphenated identifier (~11-12 characters).
     *
     * @return string Unique ID, e.g., '6f1a2-xyz12'
     */
    public static function generateUniqueId()
    {
        return sprintf('%s-%s', substr(uniqid(), -5), wp_generate_password(5, false, false));
    }

    public static function getStatusText($text)
    {
        if (!$text) {
            return '';
        }

        $mapStatus = [
            'subscribed'     => __('Subscribed', 'fluent-crm'),
            'pending'        => __('Pending', 'fluent-crm'),
            'unsubscribed'   => __('Unsubscribed', 'fluent-crm'),
            'transactional'  => __('Transactional', 'fluent-crm'),
            'bounced'        => __('Bounced', 'fluent-crm'),
            'complained'     => __('Complained', 'fluent-crm'),
            'spammed'        => __('Spammed', 'fluent-crm'),
            'checkout-draft' => __('Checkout Draft', 'fluent-crm'),
            'completed'      => __('Completed', 'fluent-crm'),
            'complete'       => __('Complete', 'fluent-crm'),
            'on-draft'       => __('On Draft', 'fluent-crm'),
            'cancelled'      => __('Cancelled', 'fluent-crm'),
            'processing'     => __('Processing', 'fluent-crm'),
            'paid'           => __('Paid', 'fluent-crm'),
            'success'        => __('Success', 'fluent-crm')
        ];

        $mapStatus = apply_filters('fluent_crm/status_text', $mapStatus);

        return isset($mapStatus[$text]) ? $mapStatus[$text] : ucfirst($text);
    }

    public static function wasProcessedByKeyId($emailLogId)
    {
        static $sentIds = [];

        if (isset($sentIds[$emailLogId])) {
            return true;
        }

        $sentIds[$emailLogId] = true;

        return false;
    }

    public static function setInstantOption($optionKey, $value, $expire = 300)
    {
        if (wp_using_ext_object_cache()) {
            return wp_cache_set($optionKey, $value, 'fc_instant_options', $expire);
        }

        return update_option($optionKey, $value, false);
    }

    public static function getInstantOption($optionKey)
    {
        if (wp_using_ext_object_cache()) {
            return wp_cache_get($optionKey, 'fc_instant_options');
        }

        return get_option($optionKey);
    }

    /**
     * Acquire a cross-process mutex via a single atomic conditional UPDATE on
     * wp_options, keyed off a stored timestamp.
     *
     * Why DB and not wp_cache_add(): wp_cache_add() is only atomic if the active
     * object-cache drop-in implements it against the shared backend. Some do NOT
     * — notably LiteSpeed Object Cache, whose add() only checks the per-process
     * in-memory array and then unconditionally writes (no Memcached ADD / Redis
     * SET NX). Under that drop-in every concurrent worker "wins" the lock, so the
     * mailer ran multiple senders at once and overshot the provider rate limit.
     * A single-row conditional UPDATE is atomic via the InnoDB row lock on every
     * backend, mirroring the CAS used by GlobalRateLimiter.
     *
     * The UPDATE claims the lock only if it is free (empty value) or stale
     * (stored timestamp older than $ttl), so a crashed holder self-recovers after
     * the TTL.
     *
     * @param string $key wp_options option_name holding the lock timestamp.
     * @param int    $ttl Seconds before a held lock is treated as abandoned.
     * @return bool True if this process acquired the lock.
     */
    public static function acquireDbLock($key, $ttl)
    {
        global $wpdb;
        $now = time();

        // Ensure the row exists so the conditional UPDATE has a row to claim.
        $wpdb->query($wpdb->prepare(
            "INSERT IGNORE INTO {$wpdb->options} (option_name, option_value, autoload) VALUES (%s, %s, %s)",
            $key, '', 'no'
        ));

        // Atomic: claim only if free or expired. Empty string casts to 0, so the
        // explicit '' check is what frees a cleanly released lock.
        $affected = $wpdb->query($wpdb->prepare(
            "UPDATE {$wpdb->options} SET option_value = %s WHERE option_name = %s AND (option_value = '' OR option_value < %d)",
            (string)$now, $key, $now - $ttl
        ));

        if ($affected > 0) {
            wp_cache_delete($key, 'options');
            return true;
        }

        return false;
    }

    /**
     * Heartbeat a held lock: push its timestamp to now so the TTL-based stale
     * detection in acquireDbLock() cannot steal it mid-run. Caller must already
     * hold the lock.
     *
     * @param string $key wp_options option_name holding the lock timestamp.
     * @return void
     */
    public static function refreshDbLock($key)
    {
        global $wpdb;
        $wpdb->query($wpdb->prepare(
            "UPDATE {$wpdb->options} SET option_value = %s WHERE option_name = %s",
            (string)time(), $key
        ));
        wp_cache_delete($key, 'options');
    }

    /**
     * Release a lock by clearing its timestamp so the next acquireDbLock() wins
     * immediately instead of waiting out the TTL. Safe to call even if this
     * process does not hold the lock (worst case frees the slot a tick early).
     *
     * @param string $key wp_options option_name holding the lock timestamp.
     * @return void
     */
    public static function releaseDbLock($key)
    {
        global $wpdb;
        $wpdb->query($wpdb->prepare(
            "UPDATE {$wpdb->options} SET option_value = '' WHERE option_name = %s",
            $key
        ));
        wp_cache_delete($key, 'options');
    }

    /**
     * Read the timestamp a lock was last (re)acquired with, straight from the
     * wp_options row that acquireDbLock()/refreshDbLock() write to.
     *
     * Reads via raw SQL — NOT getInstantOption() — so it returns the live lock
     * value regardless of external-object-cache mode. getInstantOption() reads
     * the `fc_instant_options` cache group when an object cache is active, but
     * the DB locks never write there, so it would always miss a held lock on
     * those sites. Mirrors GlobalRateLimiter's direct-read approach.
     *
     * @param string $key wp_options option_name holding the lock timestamp.
     * @return int Unix timestamp of the last (re)acquire, or 0 if free/absent.
     */
    public static function getDbLockTimestamp($key)
    {
        global $wpdb;

        $value = $wpdb->get_var($wpdb->prepare(
            "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s",
            $key
        ));

        return (int) $value;
    }

}
