<?php

/**
 * Plugin Name: AfriRegions City & Neighborhood for WooCommerce
 * Description: Structured address fields for WooCommerce — cascading regions, cities, and neighborhoods with zone-based shipping and address validation.
 * Version: 1.0.8
 * Author: woonet237
 * Author URI: https://afriregions.com
 * Text Domain: afriregions-city-neighborhood-for-woocommerce
 * Domain Path: /languages
 * License: GPLv2 or later
 * License URI: http://www.gnu.org/licenses/gpl-2.0.html
 * Requires at least: 5.8
 * Tested up to: 7.0
 * Requires PHP: 7.4
 * Requires Plugins: woocommerce
 * WC requires at least: 6.0
 * WC tested up to: 9.4
 *
 */

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

if ( ! defined( 'SCPWOO_PLUGIN_FILE' ) ) {
    define( 'SCPWOO_PLUGIN_FILE', __FILE__ );
}

// =====================================================================
// Freemius SDK Integration
// =====================================================================

if ( function_exists( 'afr_fs' ) ) {
    afr_fs()->set_basename( false, __FILE__ );
} else {
    /**
     * DO NOT REMOVE THIS IF, IT IS ESSENTIAL FOR THE
     * `function_exists` CALL ABOVE TO PROPERLY WORK.
     */
    if ( ! function_exists( 'afr_fs' ) ) {
        // Create a helper function for easy SDK access.
        function afr_fs() {
            global $afr_fs;

            if ( ! isset( $afr_fs ) ) {
                // Include Freemius SDK.
                require_once dirname( __FILE__ ) . '/vendor/freemius/start.php';

                $afr_fs = fs_dynamic_init( array(
                    'id'                  => '27297',
                    'slug'                => 'afriregions',
                    'premium_slug'        => 'afriregions-pro',
                    'type'                => 'plugin',
                    'public_key'          => 'pk_b79fa1cb1dfe7080a0811bc844580',
                    'is_premium'          => false,
                    'premium_suffix'      => 'Pro',
                    'has_premium_version' => true,
                    'has_addons'          => false,
                    'has_paid_plans'      => true,
                    'is_org_compliant'    => true,
                    'menu'                => array(
                        'slug'       => 'scpwoo',
                        'first-path' => 'admin.php?page=scpwoo',
                        'pricing'    => true,
                        'support'    => false,
                    ),
                ) );
            }

            return $afr_fs;
        }

        // Init Freemius.
        afr_fs();
        // Signal that SDK was initiated.
        do_action( 'afr_fs_loaded' );

        // Uninstall cleanup — runs after Freemius tracks the uninstall event.
        afr_fs()->add_action( 'after_uninstall', 'afr_fs_uninstall_cleanup' );

        // Custom pricing page styling.
        afr_fs()->add_filter( 'pricing/css_path', function() {
            return dirname( __FILE__ ) . '/admin/css/freemius-pricing.css';
        } );

        // Show annual price, not monthly equivalent.
        afr_fs()->add_filter( 'pricing/show_annual_in_monthly', '__return_false' );

        // Custom plugin icon for opt-in screen.
        afr_fs()->add_filter( 'plugin_icon', function() {
            return dirname( __FILE__ ) . '/admin/img/afriregions-icon.svg';
        } );

        // Inject testimonials on pricing page.
        add_action( 'admin_footer', function() {
            $screen = get_current_screen();
            if ( ! $screen || strpos( $screen->id, 'scpwoo-pricing' ) === false ) {
                return;
            }
            ?>
            <div id="afr-testimonials">
                <h3 class="afr-testimonials-title"><?php esc_html_e( 'Trusted by African e-commerce businesses', 'afriregions-city-neighborhood-for-woocommerce' ); ?></h3>
                <div class="afr-testimonials-track">

                    <div class="afr-testimonial-card">
                        <div class="afr-stars">&#9733;&#9733;&#9733;&#9733;&#9733;</div>
                        <p class="afr-quote">"Avant AfriRegions, 1 commande sur 3 avait une adresse incompl&egrave;te. Maintenant les livreurs trouvent les clients du premier coup. Le ROI est imm&eacute;diat."</p>
                        <div class="afr-author">
                            <strong>Emmanuel M.</strong>
                            <span>Directeur E-commerce</span>
                        </div>
                    </div>

                    <div class="afr-testimonial-card">
                        <div class="afr-stars">&#9733;&#9733;&#9733;&#9733;&#9733;</div>
                        <p class="afr-quote">"Le Point Relais a doubl&eacute; nos commandes en zone p&eacute;ri-urbaine. Les clients qui h&eacute;sitaient &agrave; cause de l'adresse commandent maintenant sans probl&egrave;me."</p>
                        <div class="afr-author">
                            <strong>Fatou S.</strong>
                            <span>Fondatrice, boutique mode</span>
                        </div>
                    </div>

                    <div class="afr-testimonial-card">
                        <div class="afr-stars">&#9733;&#9733;&#9733;&#9733;&#9733;</div>
                        <p class="afr-quote">"L'Agence de Voyage r&eacute;pond &agrave; un vrai besoin. Nos clients &agrave; Bafoussam, Bertoua, Maroua re&ccedil;oivent leurs colis via les bus comme ils en ont l'habitude."</p>
                        <div class="afr-author">
                            <strong>Jean-Pierre K.</strong>
                            <span>G&eacute;rant marketplace</span>
                        </div>
                    </div>

                    <div class="afr-testimonial-card">
                        <div class="afr-stars">&#9733;&#9733;&#9733;&#9733;&#9733;</div>
                        <p class="afr-quote">"Smart Search a r&eacute;duit le temps de remplissage du checkout de 45 secondes &agrave; 8 secondes. Les abandons de panier ont chut&eacute; de 35%."</p>
                        <div class="afr-author">
                            <strong>Amina B.</strong>
                            <span>Responsable digital</span>
                        </div>
                    </div>

                    <div class="afr-testimonial-card">
                        <div class="afr-stars">&#9733;&#9733;&#9733;&#9733;&#9733;</div>
                        <p class="afr-quote">"On g&egrave;re 3 boutiques WooCommerce dans 4 pays africains. AfriRegions Pro est le seul plugin qui couvre tous nos march&eacute;s avec un seul outil."</p>
                        <div class="afr-author">
                            <strong>David O.</strong>
                            <span>CTO, agence web</span>
                        </div>
                    </div>

                    <div class="afr-testimonial-card">
                        <div class="afr-stars">&#9733;&#9733;&#9733;&#9733;&#9733;</div>
                        <p class="afr-quote">"Les statistiques par r&eacute;gion nous ont permis d'identifier que 60% de nos ventes viennent de 3 quartiers. On a ajust&eacute; notre stock et nos promos en cons&eacute;quence."</p>
                        <div class="afr-author">
                            <strong>Grace N.</strong>
                            <span>E-commerce manager</span>
                        </div>
                    </div>

                </div>
            </div>
            <style>
                #afr-testimonials { max-width: 900px; margin: 40px auto 20px; padding: 0 20px; }
                .afr-testimonials-title { text-align: center; font-size: 17px; color: #1d2327; margin-bottom: 18px; }
                .afr-testimonials-track {
                    display: flex;
                    gap: 14px;
                    overflow-x: auto;
                    scroll-snap-type: x mandatory;
                    -webkit-overflow-scrolling: touch;
                    padding-bottom: 12px;
                    scrollbar-width: thin;
                    scrollbar-color: #C2703E #f0f0f0;
                }
                .afr-testimonials-track::-webkit-scrollbar { height: 6px; }
                .afr-testimonials-track::-webkit-scrollbar-track { background: #f0f0f0; border-radius: 3px; }
                .afr-testimonials-track::-webkit-scrollbar-thumb { background: #C2703E; border-radius: 3px; }
                .afr-testimonial-card {
                    flex: 0 0 280px;
                    scroll-snap-align: start;
                    background: #fff;
                    border: 1px solid #e0e0e0;
                    border-radius: 10px;
                    padding: 20px;
                    transition: box-shadow 0.2s;
                }
                .afr-testimonial-card:hover { box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
                .afr-stars { color: #C2703E; font-size: 15px; margin-bottom: 10px; letter-spacing: 2px; }
                .afr-quote { font-size: 13px; color: #646970; line-height: 1.6; margin: 0 0 14px; font-style: italic; }
                .afr-author strong { display: block; font-size: 13px; color: #1d2327; }
                .afr-author span { font-size: 11px; color: #8c8f94; }
            </style>
            <script>
                jQuery(function($){
                    var $t = $('#afr-testimonials').detach();
                    $('#fs_pricing').append($t);
                });
            </script>
            <?php
        } );

        // Hide Pricing menu for paying users.
        afr_fs()->add_filter( 'is_submenu_visible', function( $is_visible, $menu_id ) {
            if ( 'pricing' === $menu_id ) {
                return ! afr_fs()->is_paying_or_trial();
            }
            return $is_visible;
        }, 10, 2 );

        // Hide tabs on Freemius screens.
        afr_fs()->add_filter( 'hide_account_tabs', '__return_true' );
    }

    /**
     * Plugin cleanup on uninstall.
     * Called by Freemius after_uninstall action.
     */
    function afr_fs_uninstall_cleanup() {
        global $wpdb;

        // Drop plugin tables
        $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}scpwoo_geodata" );
        $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}scpwoo_audit_log" );
        delete_option( 'scpwoo_db_version' );
        delete_option( 'scpwoo_audit_db_version' );

        // Order and user meta keys
        $order_meta_keys = array(
            '_billing_neighborhood', '_shipping_neighborhood',
        );
        $user_meta_keys = array(
            'billing_neighborhood', 'shipping_neighborhood',
        );

        // Delete order meta
        $placeholders = implode( ',', array_fill( 0, count( $order_meta_keys ), '%s' ) );
        $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->postmeta} WHERE meta_key IN ($placeholders)", $order_meta_keys ) );

        // Delete user meta
        $placeholders = implode( ',', array_fill( 0, count( $user_meta_keys ), '%s' ) );
        $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->usermeta} WHERE meta_key IN ($placeholders)", $user_meta_keys ) );

        // Delete options
        delete_option( 'scpwoo_custom_places' );
        delete_option( 'scpwoo_custom_neighborhoods' );
        delete_option( 'scpwoo_settings' );
        delete_option( 'scpwoo_restricted_zones' );
        delete_option( 'scpwoo_activation_redirect' );

        // Delete transients
        $like1 = $wpdb->esc_like( '_transient_scpwoo_stats_' ) . '%';
        $like2 = $wpdb->esc_like( '_transient_timeout_scpwoo_stats_' ) . '%';
        $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s", $like1, $like2 ) );
        delete_transient( 'scpwoo_dashboard_orders' );

        // Delete shipping method options
        $like = $wpdb->esc_like( 'woocommerce_scpwoo_' ) . '%' . $wpdb->esc_like( '_settings' );
        $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", $like ) );

        // HPOS: delete from wc_orders_meta if table exists
        $hpos_table = $wpdb->prefix . 'wc_orders_meta';
        if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $hpos_table ) ) === $hpos_table ) {
            $placeholders = implode( ',', array_fill( 0, count( $order_meta_keys ), '%s' ) );
            $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}wc_orders_meta WHERE meta_key IN ($placeholders)", $order_meta_keys ) );
        }
    }

    // =====================================================================
    // Plugin Logic
    // =====================================================================

    /**
     * Check if WooCommerce is active
     */
    if ( ( is_multisite() && array_key_exists( 'woocommerce/woocommerce.php', get_site_option( 'active_sitewide_plugins', array() ) ) ) ||
        in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {

        class SCPWOO_States_Places {

            const VERSION = '1.0.8';

            // WordPress option keys
            const OPTION_SETTINGS         = 'scpwoo_settings';
            const OPTION_CUSTOM_PLACES    = 'scpwoo_custom_places';
            const OPTION_CUSTOM_HOODS     = 'scpwoo_custom_neighborhoods';
            const OPTION_RESTRICTED_ZONES = 'scpwoo_restricted_zones';

            // Admin keys
            const NONCE_ADMIN       = 'scpwoo_admin_nonce';
            const NONCE_ADMIN_WRITE = 'scpwoo_admin_write_nonce';
            const META_GUIDE_DISMISSED = 'scpwoo_guide_dismissed';

            // Input limits
            const MAX_LEN_CITY         = 100;
            const MAX_LEN_NEIGHBORHOOD = 100;
            const MAX_LEN_LANDMARK     = 500;
            const MAX_LEN_MESSAGE      = 500;

            // Order meta keys
            const META_BILLING_NEIGHBORHOOD  = '_billing_neighborhood';
            const META_SHIPPING_NEIGHBORHOOD = '_shipping_neighborhood';


            /** @var SCPWOO_States_Places|null Singleton instance */
            private static $instance = null;

            private $plugin_path;
            private $plugin_url;

            // =====================================================================
            // Bootstrap
            // =====================================================================

            /**
             * Get the singleton instance.
             *
             * @return SCPWOO_States_Places|null
             */
            public static function instance() {
                return self::$instance;
            }

            public function __construct() {
                self::$instance = $this;
                add_action( 'plugins_loaded', array( $this, 'init' ) );
            }

            public function init() {
                load_plugin_textdomain( 'afriregions-city-neighborhood-for-woocommerce', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );

                add_action( 'before_woocommerce_init', array( $this, 'woocommerce_hpos_compatible' ) );

                // Admin notice — always show (even if country not supported)
                if ( is_admin() ) {
                    add_action( 'admin_notices', array( $this, 'country_support_notice' ) );
                    add_action( 'wp_ajax_scpwoo_dismiss_notice', array( $this, 'ajax_dismiss_notice' ) );
                }

                // Load core dependencies early — needed by admin pages even when no country is supported.
                require_once $this->get_plugin_path() . '/includes/class-scpwoo-geo-repository.php';
                require_once $this->get_plugin_path() . '/includes/class-scpwoo-options.php';

                // Shipping methods must always be registered so they appear in
                // WooCommerce → Shipping → Zone settings regardless of country config.
                add_action( 'woocommerce_shipping_init', array( $this, 'load_shipping_class' ) );
                add_filter( 'woocommerce_shipping_methods', array( $this, 'register_shipping_method' ) );

                // Check if at least one allowed country is supported — if not, stop here
                if ( ! $this->has_supported_allowed_country() ) {
                    // Admin menu still available for info
                    if ( is_admin() ) {
                        require_once $this->get_plugin_path() . '/admin/class-scpwoo-admin.php';
                        new SCPWOO_Admin();
                    }
                    return;
                }

                // --- From here: only if country is supported ---

                // Run geo data migration if needed
                if ( SCPWOO_Geo_Repository::needs_migration() ) {
                    SCPWOO_Geo_Repository::run_migration();
                }

                // States
                add_filter( 'woocommerce_states', array( $this, 'wc_states' ) );

                // Load specialized classes
                $this->load_includes();

                // Ensure audit log table exists (after load_includes so SCPWOO_Audit is available)
                SCPWOO_Audit::maybe_create_table();

                // Admin
                if ( is_admin() ) {
                    require_once $this->get_plugin_path() . '/admin/class-scpwoo-admin.php';
                    new SCPWOO_Admin();
                }
            }

            /**
             * Load specialized classes
             */
            private function load_includes() {
                $path = $this->get_plugin_path() . '/includes/';

                require_once $path . 'class-scpwoo-geo-repository.php';
                require_once $path . 'class-scpwoo-options.php';
                require_once $this->get_plugin_path() . '/admin/class-scpwoo-audit.php';
                require_once $path . 'class-scpwoo-aliases.php';
                require_once $path . 'class-scpwoo-ajax.php';

                $ajax = new SCPWOO_Ajax( $this );
                $ajax->register_hooks();

                require_once $path . 'class-scpwoo-fields.php';
                require_once $path . 'class-scpwoo-address.php';
                require_once $path . 'class-scpwoo-scripts.php';
                require_once $path . 'class-scpwoo-rest-api.php';

                new SCPWOO_Fields();
                new SCPWOO_Address();
                new SCPWOO_Scripts();
                new SCPWOO_REST_API();
            }

            // =====================================================================
            // States (regions)
            // =====================================================================

            public function wc_states( $wc_states ) {
                $loaded = SCPWOO_Geo_Repository::get_states_by_country();
                foreach ( $loaded as $code => $country_states ) {
                    if ( ! isset( $wc_states[ $code ] ) ) {
                        $wc_states[ $code ] = $country_states;
                    }
                }
                return apply_filters( 'scpwoo_states', $wc_states );
            }

            // =====================================================================
            // Places (cities)
            // =====================================================================

            public function get_places( $p_code = null ) {
                $places = SCPWOO_Geo_Repository::get_merged_places_by_country();
                if ( ! is_null( $p_code ) ) {
                    return $places[ $p_code ] ?? false;
                }
                return $places;
            }

            // =====================================================================
            // Neighborhoods
            // =====================================================================

            public function get_neighborhoods( $p_code = null ) {
                $neighborhoods = SCPWOO_Geo_Repository::get_merged_neighborhoods_by_country();
                if ( ! is_null( $p_code ) ) {
                    return $neighborhoods[ $p_code ] ?? false;
                }
                return $neighborhoods;
            }

            // =====================================================================
            // Shipping
            // =====================================================================

            public function load_shipping_class() {
                require_once $this->get_plugin_path() . '/includes/class-wc-shipping-rcn.php';
            }

            public function register_shipping_method( $methods ) {
                $methods['scpwoo_zone_shipping'] = 'SCPWOO_Shipping_RCN';
                return $methods;
            }

            // =====================================================================
            // Helpers
            // =====================================================================

            /**
             * Get the store's base country from WooCommerce settings.
             *
             * @return string Country code (e.g. 'CM', 'GA', 'FR')
             */
            public function get_store_country() {
                $base = get_option( 'woocommerce_default_country', '' );
                // Format is 'CM' or 'CM:CE' (country:state)
                $parts = explode( ':', $base );
                return strtoupper( $parts[0] );
            }

            /**
             * Show admin notice about country support status.
             * Dismissible — only shows once per country change.
             */
            public function country_support_notice() {
                $screen = get_current_screen();
                if ( ! $screen ) return;

                $show_on = array( 'toplevel_page_scpwoo', 'woocommerce_page_wc-settings' );
                if ( ! in_array( $screen->id, $show_on, true ) && strpos( $screen->id, 'scpwoo' ) === false ) {
                    return;
                }

                // Find which allowed countries are supported
                $supported       = $this->get_supported_countries();
                $allowed         = $this->get_store_allowed_countries();
                $active_countries = array();

                if ( ! empty( $allowed ) ) {
                    foreach ( array_keys( $allowed ) as $code ) {
                        if ( in_array( strtoupper( $code ), $supported, true ) ) {
                            $active_countries[] = strtoupper( $code );
                        }
                    }
                }

                $has_supported = ! empty( $active_countries );

                // If supported and user already dismissed, don't show again
                $dismiss_key = implode( ',', $active_countries );
                $dismissed   = get_user_meta( get_current_user_id(), 'scpwoo_notice_dismissed', true );
                if ( $has_supported && $dismissed === $dismiss_key ) {
                    return;
                }

                $wc_countries = function_exists( 'WC' ) && WC()->countries ? WC()->countries->get_countries() : array();

                if ( $has_supported ) {
                    $names = array();
                    foreach ( $active_countries as $cc ) {
                        $names[] = isset( $wc_countries[ $cc ] ) ? $wc_countries[ $cc ] : $cc;
                    }
                    echo '<div class="notice notice-success is-dismissible" id="scpwoo-support-notice" data-country="' . esc_attr( $dismiss_key ) . '"><p>';
                    echo '<strong>AfriRegions City & Neighborhood for WooCommerce</strong> — ';
                    /* translators: %s = list of country names */
                    printf(
                        esc_html__( 'Active for: %s. Regions, cities and neighborhoods are available.', 'afriregions-city-neighborhood-for-woocommerce' ),
                        '<strong>' . esc_html( implode( ', ', $names ) ) . '</strong>'
                    );
                    echo '</p></div>';
                    // Dismiss handler — enqueued via wp_add_inline_script to avoid inline <script>
                    wp_add_inline_script( 'jquery-core', '
                        jQuery(function($){
                            $("#scpwoo-support-notice").on("click",".notice-dismiss",function(){
                                $.post(ajaxurl,{
                                    action:"scpwoo_dismiss_notice",
                                    country:$("#scpwoo-support-notice").data("country"),
                                    _wpnonce:' . wp_json_encode( wp_create_nonce( 'scpwoo_dismiss_notice' ) ) . '
                                });
                            });
                        });
                    ' );
                } else {
                    echo '<div class="notice notice-warning is-dismissible"><p>';
                    echo '<strong>AfriRegions City & Neighborhood for WooCommerce</strong> — ';
                    esc_html_e( 'None of your allowed countries are currently supported by this plugin.', 'afriregions-city-neighborhood-for-woocommerce' );
                    echo '<br><a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=general' ) ) . '">';
                    esc_html_e( 'Check your WooCommerce country settings', 'afriregions-city-neighborhood-for-woocommerce' );
                    echo ' &rarr;</a>';
                    echo '</p></div>';
                }
            }

            /**
             * AJAX: remember that the user dismissed the support notice for this country.
             */
            public function ajax_dismiss_notice() {
                check_ajax_referer( 'scpwoo_dismiss_notice', '_wpnonce' );

                if ( ! current_user_can( 'manage_woocommerce' ) ) {
                    wp_send_json_error( 'Unauthorized', 403 );
                }

                $country = isset( $_POST['country'] ) ? sanitize_text_field( wp_unslash( $_POST['country'] ) ) : '';
                if ( $country ) {
                    update_user_meta( get_current_user_id(), 'scpwoo_notice_dismissed', $country );
                }
                wp_send_json_success();
            }

            public function get_plugin_path() {
                if ( isset( $this->plugin_path ) ) {
                    return $this->plugin_path;
                }
                return $this->plugin_path = untrailingslashit( plugin_dir_path( __FILE__ ) );
            }

            public function get_plugin_url() {
                if ( isset( $this->plugin_url ) ) {
                    return $this->plugin_url;
                }
                return $this->plugin_url = plugin_dir_url( __FILE__ );
            }

            /**
             * Get the list of country codes that have data files in this plugin.
             * Scans the states/ directory for PHP files named by country code.
             *
             * @return array Country codes, e.g. ['CM', 'GA', 'TD']
             */
            public function get_supported_countries() {
                static $supported = null;
                if ( $supported !== null ) {
                    return $supported;
                }

                $supported = array();
                $states_dir = $this->get_plugin_path() . '/states/';
                if ( is_dir( $states_dir ) ) {
                    foreach ( glob( $states_dir . '*.php' ) as $file ) {
                        $code = strtoupper( basename( $file, '.php' ) );
                        if ( preg_match( '/^[A-Z]{2}$/', $code ) ) {
                            $supported[] = $code;
                        }
                    }
                }

                return $supported;
            }

            /**
             * Check if a country code is supported by this plugin.
             *
             * @param string $code
             * @return bool
             */
            public function is_supported_country( $code ) {
                return in_array( strtoupper( $code ), $this->get_supported_countries(), true );
            }

            /**
             * Check if at least one WooCommerce allowed/shipping country is supported.
             *
             * This is used in init() to decide whether to load the plugin's
             * frontend features. Unlike the old check that only looked at the
             * store's base country, this enables multi-country setups where
             * the base country may not be supported (e.g. base=US, ships to CM).
             *
             * @return bool
             */
            public function has_supported_allowed_country() {
                // Quick check: if the store base country is supported, return true immediately
                if ( $this->is_supported_country( $this->get_store_country() ) ) {
                    return true;
                }

                // Otherwise, check all allowed + shipping countries
                $allowed = $this->get_store_allowed_countries();
                if ( empty( $allowed ) ) {
                    return false;
                }

                $supported = $this->get_supported_countries();
                foreach ( array_keys( $allowed ) as $code ) {
                    if ( in_array( strtoupper( $code ), $supported, true ) ) {
                        return true;
                    }
                }

                return false;
            }

            /**
             * Include data files from a subdirectory and return the collected data.
             *
             * Data files (e.g. places/CM.php) use a global variable to export their arrays.
             * This method encapsulates that convention: it saves/restores the global,
             * includes each file, and returns the merged result.
             *
             * @param string $directory  Subdirectory name (e.g. 'places', 'neighborhoods', 'states').
             * @param string $global_var Name of the global variable used by data files.
             * @return array
             */
            /**
             * Get the countries for which the plugin should load data.
             *
             * Strategy:
             * 1. Get WooCommerce allowed + shipping countries
             * 2. Intersect with our supported countries (those with data files)
             * 3. If "Sell to all countries" is enabled, we load ALL supported countries
             *    (no need to limit to the full 200+ WC list)
             *
             * @return array Associative array code => name
             */
            private function get_store_allowed_countries() {
                if ( ! function_exists( 'WC' ) || ! WC()->countries ) {
                    return array();
                }

                $wc_allowed  = WC()->countries->get_allowed_countries();
                $wc_shipping = WC()->countries->get_shipping_countries();
                $all_allowed = array_merge( $wc_allowed, $wc_shipping );

                // If WooCommerce is set to "Sell to all countries" or "Ship to all countries",
                // the list will contain 200+ countries. In that case, just return our
                // supported countries so we don't unnecessarily try to load data for
                // countries we don't support.
                $supported = $this->get_supported_countries();

                // Build result: only countries we support AND that WC allows
                $result = array();

                foreach ( $supported as $cc ) {
                    if ( isset( $all_allowed[ $cc ] ) ) {
                        $result[ $cc ] = $all_allowed[ $cc ];
                    }
                }

                // If result is empty, it means none of our supported countries
                // are in the allowed list. This can happen when the admin hasn't
                // explicitly added them. Fall back to supported countries that
                // match the store's base country at minimum.
                if ( empty( $result ) ) {
                    $base = $this->get_store_country();
                    if ( in_array( $base, $supported, true ) && isset( $wc_all_countries[ $base ] ) ) {
                        $result[ $base ] = $wc_all_countries[ $base ];
                    }
                }

                return $result;
            }

            // =====================================================================
            // Safe option storage (JSON, not PHP serialize) — delegated
            // =====================================================================

            public static function get_json_option( string $key, array $default = array() ): array {
                return SCPWOO_Options::get_json_option( $key, $default );
            }

            public static function update_json_option( string $key, array $data ): bool {
                return SCPWOO_Options::update_json_option( $key, $data );
            }

            // =====================================================================
            // HPOS
            // =====================================================================

            public function woocommerce_hpos_compatible() {
                if ( class_exists( '\Automattic\WooCommerce\Utilities\FeaturesUtil' ) ) {
                    \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, true );
                }
            }
        }

        new SCPWOO_States_Places();

        /**
         * Activation: cleanup flag (no auto-creation of shipping zones).
         * Users create their own zones via WooCommerce → Shipping.
         */
        register_activation_hook( SCPWOO_PLUGIN_FILE, function() {
            delete_option( 'scpwoo_activation_redirect' );
            // Ensure large legacy options are not autoloaded on every request.
            foreach ( array( 'scpwoo_custom_places', 'scpwoo_custom_neighborhoods' ) as $opt ) {
                $value = get_option( $opt );
                if ( $value !== false ) {
                    update_option( $opt, $value, false );
                }
            }
            // Schedule daily audit log retention (90 days).
            if ( ! wp_next_scheduled( 'scpwoo_audit_retention' ) ) {
                wp_schedule_event( time(), 'daily', 'scpwoo_audit_retention' );
            }
        } );

        add_action( 'scpwoo_audit_retention', function() {
            if ( class_exists( 'SCPWOO_Audit' ) ) {
                SCPWOO_Audit::purge_old_entries( 90 );
            }
        } );

        register_deactivation_hook( SCPWOO_PLUGIN_FILE, function() {
            wp_clear_scheduled_hook( 'scpwoo_audit_retention' );
            $instance = SCPWOO_States_Places::instance();
            if ( $instance ) {
                remove_filter( 'woocommerce_states', array( $instance, 'wc_states' ) );
                remove_filter( 'woocommerce_shipping_methods', array( $instance, 'register_shipping_method' ) );
            }
        } );

        /**
         * Add "Settings" link on the Plugins page
         */
        add_filter( 'plugin_action_links_' . plugin_basename( SCPWOO_PLUGIN_FILE ), function( $links ) {
            $settings_link = '<a href="' . esc_url( admin_url( 'admin.php?page=scpwoo&tab=settings' ) ) . '">'
                . esc_html__( 'Settings', 'afriregions-city-neighborhood-for-woocommerce' ) . '</a>';
            array_unshift( $links, $settings_link );
            return $links;
        } );

    }; // end WooCommerce check
} // end Freemius else
