<?php

namespace ArraySubs;

defined('ABSPATH') || exit;


use ArraySubs\Features;
use ArraySubs\Supports\Config;
use ArraySubs\Supports\CustomEndpoints;

class Boot
{
    public function __construct()
    {
        Config::add('plugin.src_path', __DIR__);

        add_action('admin_enqueue_scripts', [$this, 'enqueueAdminAssets'], 9);
        add_action('init', [$this, 'registerCronSchedules']);
        add_action('parse_request', [$this, 'routePrettyRestFallback'], 0);
        add_filter('action_scheduler_allow_async_request_runner', [$this, 'allowActionSchedulerAsyncRequestRunner']);

        $liveBootClasses = [];
        $filteredBootClasses = apply_filters('arraysubs_boot_classes', [

            // Members Access (Content Gating / Membership)
            Features\MembersAccess\Provider::class,

            // Skip Renewal / Vacation Mode (skip cycles, pause subscriptions)
            Features\SkipRenewal\Provider::class,

            // Product Lifecycle (handle product deletion affecting subscriptions)
            Features\ProductLifecycle\Provider::class,
        ]);

        $filteredBootClasses = array_merge([
            // Supports
            CustomEndpoints::class,
            Features\MainAdmin\Provider::class,
            Features\CustomerPortal\Provider::class,
            Features\ProductEdit\Provider::class,

            // Core Subscription Features
            Features\Subscriptions\Provider::class,
            Features\SubscriptionProducts\Provider::class,
            Features\SubscriptionCheckout\Provider::class,
            Features\RecurringBilling\Provider::class,
            Features\SubscriptionAdmin\Provider::class,
            Features\SubscriptionNotes\Provider::class,
            Features\Emails\Provider::class,

            // Cancellation, Plan Switching & Refunds
            Features\CancellationFlow\Provider::class,
            Features\PlanSwitching\Provider::class,
            Features\Refunds\Provider::class,

            // Coupon Tracking (recurring discounts on renewals)
            Features\CouponTracking\Provider::class,

            // Analytics
            Features\RetentionAnalytics\Provider::class,

            // Member Shortcodes (login, logout, user, visibility)
            Features\MemberShortcodes\Provider::class,

            // Elementor Integration (container restriction controls)
            Features\ElementorIntegration\Provider::class,

            // Gutenberg Integration (content restricted container block)
            Features\GutenbergIntegration\Provider::class,

            // Login as User (admin impersonation)
            Features\LoginAsUser\Provider::class,

            // Profile Fields (custom fields + avatar on accounts)
            Features\ProfileFields\Provider::class,

            // My Account Editor (reorder menu, add custom pages)
            Features\MyAccountEditor\Provider::class,

            // Easy Setup (import/export settings)
            Features\EasySetup\Provider::class,

        ], $filteredBootClasses);

        if (!is_array($filteredBootClasses) || empty($filteredBootClasses)) {
            return;
        }

        foreach ($filteredBootClasses as $bootClass) {
            if (!is_string($bootClass) || !class_exists($bootClass)) {
                continue;
            }

            $liveBootClasses[] = $bootClass;
            new $bootClass();
        }

        // add live boot classes to config for reference (if needed by other parts of the plugin)
        Config::add('live_boot_classes', $liveBootClasses);
    }

    /**
     * Prevent admin/web traffic from draining due scheduled actions when WP-Cron is disabled.
     *
     * @param bool $allow Current Action Scheduler async-runner decision.
     * @return bool
     */
    public function allowActionSchedulerAsyncRequestRunner(bool $allow): bool
    {
        if (defined('DISABLE_WP_CRON') && DISABLE_WP_CRON) {
            return false;
        }

        return $allow;
    }

    /**
     * Route ArraySubs pretty REST URLs when WordPress has no rewrite rules.
     *
     * @param \WP $wp WordPress request object.
     * @return void
     */
    public function routePrettyRestFallback(\WP $wp): void
    {
        if (!empty($wp->query_vars['rest_route'])) {
            return;
        }

        $request_uri = (string) ($_SERVER['REQUEST_URI'] ?? '');
        $path = wp_parse_url($request_uri, PHP_URL_PATH);

        if (!is_string($path) || $path === '') {
            return;
        }

        $rest_prefix = '/' . trim(rest_get_url_prefix(), '/');
        $marker = $rest_prefix . '/arraysubs/v1/';
        $marker_position = strpos($path, $marker);

        if ($marker_position === false) {
            return;
        }

        $route = '/' . ltrim(substr($path, $marker_position + strlen($rest_prefix)), '/');
        $route = untrailingslashit(rawurldecode($route));

        if (strpos($route, '/arraysubs/v1/') !== 0) {
            return;
        }

        $wp->query_vars['rest_route'] = $route;
        $_GET['rest_route'] = $route;
    }

    public function enqueueAdminAssets()
    {
        // Only load on app page
        if (
            !is_admin()
        ) {
            return;
        }

        // Load dependencies from webpack asset file
        $asset_file = Config::get('plugin.public_path') . 'build/boot.asset.php';
        $asset = file_exists($asset_file) ? require $asset_file : ['dependencies' => ['react', 'react-dom', 'react-jsx-runtime'], 'version' => ARRAYSUBS_VERSION];

        wp_enqueue_script(
            'arraysubs-boot',
            Config::get('plugin.public_url') . 'build/boot.js',
            $asset['dependencies'],
            $asset['version'],
            true
        );

        // Set the public path for webpack chunk loading BEFORE the script executes
        $arraysubs_json_flags = JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT;

        wp_add_inline_script(
            'arraysubs-boot',
            'window.arraySubs.publicPath = ' . wp_json_encode(Config::get('plugin.public_url') . 'build/', $arraysubs_json_flags) . '; ' .
                'window.arraySubs.env = ' . wp_json_encode($this->reactEnvVars(), $arraysubs_json_flags) . ';' .
                'window.arraySubs.settings = ' . wp_json_encode($this->reactSettingsVars(), $arraysubs_json_flags) . ';' .
                'window.arraySubs.liveBootClasses = ' . wp_json_encode(Config::get('live_boot_classes'), $arraysubs_json_flags) . ';',
            'after'
        );
    }

    /**
     * Adds JavaScript variables to the admin head.
     *
     * @return array
     */
    public function reactEnvVars(): array
    {
        $countries = [];
        $shipping_countries = [];
        $states = [];

        if (function_exists('WC') && WC() && !empty(WC()->countries)) {
            $countries = WC()->countries->get_allowed_countries();
            $shipping_countries = WC()->countries->get_shipping_countries();
            $states = WC()->countries->get_states();
        }

        return [
            'version' => ARRAYSUBS_VERSION,
            'appTitle' => esc_html__('ArraySubs', 'arraysubs'),
            'defaultLocale' => get_locale() ?: 'en_US',
            // get wp timezone and format
            'timezone' => wp_timezone_string() ?: 'UTC',
            'gmtOffset' => (float) get_option('gmt_offset', 0),
            'dateFormat' => get_option('date_format') ?: 'Y-m-d',
            'timeFormat' => get_option('time_format') ?: 'H:i:s',
            'mainadminRootDomId' => 'arraysubs-mainadmin-root',
            'publicUrl' => esc_url_raw(Config::get('plugin.public_url')),
            'nonce' => wp_create_nonce('wp_rest'),
            'apiBaseUrl' => esc_url_raw(rest_url()),
            'wpAdminUrl' => esc_url_raw(Config::get('wp.wp_admin_url')),
            'countries' => $countries,
            'shippingCountries' => $shipping_countries,
            'states' => $states,
        ];
    }

    private function reactSettingsVars(): array
    {
        $settings = arraysubs_get_settings();

        return [
            'toolkit' => [
                'multi_login_prevention' => !empty($settings['toolkit']['multi_login_prevention']),
            ],
        ];
    }

    /**
     * Register cron schedules for attachment cleanup.
     *
     * @return void
     */
    public function registerCronSchedules(): void {}
}
