<?php

/**
 * Plugin Name:       Australcode Points and Rewards for WooCommerce
 * Plugin URI:        https://points-rewards.australcode.io
 * Description:       Loyalty points and rewards for WooCommerce: earn on purchases with per-product, per-category and per-role rules, redeem points for cart discounts, a My Account rewards area, a floating widget, shortcodes/blocks and dark mode. Pro adds VIP tiers, time-boxed campaigns, signup/daily-login/first-order/review/birthday bonuses, two-sided referrals and points expiration.
 * Version:           1.0.1
 * Requires at least: 6.5
 * Requires PHP:      8.2
 * Author:            Australcode
 * Author URI:        https://australcode.io
 * License:           GPL-2.0-or-later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       australcode-points-rewards
 * Domain Path:       /languages
 * Requires Plugins:  woocommerce
 * WC requires at least: 9.0
 * WC tested up to: 10.7
 *
 * Freemius premium-only: archivos/carpetas de features Pro que el deploy de Freemius
 * remueve del ZIP free de WordPress.org (WP.org no permite features bloqueadas por
 * licencia en el ZIP alojado — Guideline 5, Trialware). Todo registro/binding de estas
 * clases va detrás de class_exists() (Container/Plugin), y el earning core las consume
 * vía el filtro `acrwd_earning_multiplier` en vez de tiparlas, así el ZIP free no fatala
 * al faltar el archivo. Verificar SIEMPRE el strip sobre el free build generado por
 * Freemius (canon freemius-api-skill/references/dual-zip-build.md).
 *
 *
 * @package Australcode\Rewards
 */
declare (strict_types = 1);
use Australcode\Rewards\Activator;
use Australcode\Rewards\Deactivator;
use Australcode\Rewards\Plugin;
use Australcode\Rewards\Uninstaller;
defined( 'ABSPATH' ) || exit;
/*
 * This bootstrap file lives in the GLOBAL namespace (not Australcode\Rewards) so
 * the Freemius helper acrwd_fs() is a GLOBAL function — the SDK and the
 * FreemiusSdkGateway adapter resolve it unqualified. A namespaced main file would
 * define it as Australcode\Rewards\acrwd_fs, which function_exists('acrwd_fs')
 * (global) never finds, silently degrading every license check to Free. Plugin
 * classes keep the Australcode\Rewards\ PSR-4 namespace; only this entry file is
 * global, imported via the `use` statements above (mirrors the Australcode family).
 */
/*
 * --------------------------------------------------------------------------
 * Constants
 * --------------------------------------------------------------------------
 * Naming canon: ACRWD_* constants, Australcode\Rewards\ namespace,
 * australcode-points-rewards text domain, wp_acrwd_* tables, acrwd_* hooks.
 * See docs/architecture.md.
 *
 * Guards `defined() ||`: during the free→premium switch (or vice versa) WordPress
 * can load both main files for an instant; without the guard the second define()
 * emits "already defined" warnings (gotcha #16 of the Australcode family).
 */
defined( 'ACRWD_VERSION' ) || define( 'ACRWD_VERSION', '1.0.1' );
defined( 'ACRWD_FILE' ) || define( 'ACRWD_FILE', __FILE__ );
defined( 'ACRWD_PATH' ) || define( 'ACRWD_PATH', plugin_dir_path( __FILE__ ) );
defined( 'ACRWD_URL' ) || define( 'ACRWD_URL', plugin_dir_url( __FILE__ ) );
defined( 'ACRWD_BASENAME' ) || define( 'ACRWD_BASENAME', plugin_basename( __FILE__ ) );
defined( 'ACRWD_MIN_PHP' ) || define( 'ACRWD_MIN_PHP', '8.2' );
defined( 'ACRWD_MIN_WP' ) || define( 'ACRWD_MIN_WP', '6.5' );
defined( 'ACRWD_MIN_WC' ) || define( 'ACRWD_MIN_WC', '9.0' );
/*
 * --------------------------------------------------------------------------
 * Composer autoloader
 * --------------------------------------------------------------------------
 * If vendor/ is missing (e.g. cloned without `composer install`), surface an
 * admin notice instead of fataling, and bail out early.
 */
$acrwd_autoload = ACRWD_PATH . 'vendor/autoload.php';
if ( !is_readable( $acrwd_autoload ) ) {
    add_action( 'admin_notices', static function () : void {
        echo '<div class="notice notice-error"><p>';
        echo esc_html__( 'Australcode Points and Rewards: missing Composer dependencies. Run "composer install" in the plugin directory.', 'australcode-points-rewards' );
        echo '</p></div>';
    } );
    return;
}
require $acrwd_autoload;
/*
 * --------------------------------------------------------------------------
 * Freemius SDK — billing / licensing (Lemon Squeezy → Freemius migration, 2026-06-09)
 * --------------------------------------------------------------------------
 * Product 31688 in the Australcode Freemius store. The id and public_key are
 * public by design (they ship in the distributed ZIP) — NOT the developer pk,
 * and NOT the product secret_key (sk_), which never leaves a sandbox wp-config.
 * The wp_org_gatekeeper is a secret: a placeholder ships in the repo (rule §8.1)
 * and build-zip.sh injects the real value from BWS when building the premium ZIP.
 * Its WP.org safeguard purpose only applies when publishing to WordPress.org
 * (deferred). Freemius generates the gatekeeper once paid plans exist (Fase 5).
 *
 * Opt-in is WP.org-compliant: is_org_compliant + anonymous_mode +
 * is_enable_anonymous (the Skip button is shown). No feature is gated by the
 * opt-in — the free plugin is 100% functional without it.
 */
if ( !function_exists( 'acrwd_fs' ) ) {
    /**
     * Freemius SDK singleton.
     *
     * @return \Freemius|null Null only if the SDK is absent (build without
     *                        composer install); the guard avoids a fatal.
     */
    function acrwd_fs() {
        global $acrwd_fs;
        if ( !isset( $acrwd_fs ) ) {
            $acrwd_fs_lib = ACRWD_PATH . 'vendor/freemius/wordpress-sdk/start.php';
            if ( !file_exists( $acrwd_fs_lib ) ) {
                $acrwd_fs = null;
                return $acrwd_fs;
            }
            require_once $acrwd_fs_lib;
            // The SDK only defines fs_dynamic_init() once it elects itself the
            // newest active Freemius SDK AND its plugin is a registered active
            // plugin. In contexts that load this file without that registration
            // (e.g. the WP integration-test harness requiring the plugin at
            // muplugins_loaded), fs_dynamic_init() can stay undefined — degrade to
            // Free instead of fataling (the adapter handles null). In production
            // (a real active plugin) it is always defined.
            if ( !function_exists( 'fs_dynamic_init' ) ) {
                $acrwd_fs = null;
                return $acrwd_fs;
            }
            $acrwd_fs = fs_dynamic_init( array(
                'id'                  => '31688',
                'slug'                => 'australcode-points-rewards',
                'premium_slug'        => 'australcode-points-rewards-premium',
                'type'                => 'plugin',
                'public_key'          => 'pk_4771fae50dfb939b5dd5df57c44fd',
                'is_premium'          => false,
                'premium_suffix'      => '',
                'has_addons'          => false,
                'has_paid_plans'      => true,
                'is_org_compliant'    => true,
                'anonymous_mode'      => true,
                'is_enable_anonymous' => true,
                'menu'                => array(
                    'slug'    => 'acrwd',
                    'support' => false,
                ),
                'is_live'             => true,
            ) );
        }
        return $acrwd_fs;
    }

    acrwd_fs();
    if ( null !== acrwd_fs() ) {
        // Uninstall cleanup via the SDK hook. Freemius requires the cleanup to live
        // in `after_uninstall` (NOT a root uninstall.php, which the SDK cannot
        // intercept to track the event → it rejects the deploy with HTTP 400). The
        // callback ships in both the free and premium builds and honors the opt-in
        // `delete_data_on_uninstall` setting (OFF by default → data survives reinstall).
        acrwd_fs()->add_action( 'after_uninstall', array(Uninstaller::class, 'uninstall') );
        // Icon for the SDK screens (opt-in/connect, Account). Filesystem path, not
        // URL (Freemius sdk-hooks canon; same pattern as Australcode Uniform Images).
        // Without it the first Freemius surface the user sees shows a generic placeholder.
        acrwd_fs()->add_filter( 'plugin_icon', static function () : string {
            return ACRWD_PATH . 'assets/img/plugin-icon.png';
        } );
    }
    do_action( 'acrwd_fs_loaded' );
}
/*
 * --------------------------------------------------------------------------
 * Internationalization
 * --------------------------------------------------------------------------
 * WordPress.org auto-loads translations for hosted plugins from WP 4.6, but the
 * bundled `.mo` files (es_ES, es_CL) only load when requested explicitly. Priority
 * -1 so the text domain is ready before anything on `init` emits a string.
 */
add_action( 'init', static function () : void {
    load_plugin_textdomain( 'australcode-points-rewards', false, dirname( plugin_basename( ACRWD_FILE ) ) . '/languages' );
}, -1 );
/*
 * --------------------------------------------------------------------------
 * WooCommerce feature compatibility (declared before WC initializes)
 * --------------------------------------------------------------------------
 */
add_action( 'before_woocommerce_init', static function () : void {
    if ( !class_exists( \Automattic\WooCommerce\Utilities\FeaturesUtil::class ) ) {
        return;
    }
    \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', ACRWD_FILE, true );
    \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'cart_checkout_blocks', ACRWD_FILE, true );
} );
/*
 * --------------------------------------------------------------------------
 * Lifecycle hooks
 * --------------------------------------------------------------------------
 */
register_activation_hook( ACRWD_FILE, array(Activator::class, 'activate') );
register_deactivation_hook( ACRWD_FILE, array(Deactivator::class, 'deactivate') );
/*
 * --------------------------------------------------------------------------
 * Boot
 * --------------------------------------------------------------------------
 * Priority 20 so WooCommerce (priority 10) is fully loaded first.
 */
add_action( 'plugins_loaded', static function () : void {
    Plugin::instance()->boot();
}, 20 );