<?php

/**
 * PlanSwitching Hooks
 *
 * Handles product meta for upgrade/downgrade products
 * and integrates with WooCommerce product edit.
 *
 * @package ArraySubs\Features\PlanSwitching\Services
 * @since 1.0.0
 */

namespace ArraySubs\Features\PlanSwitching\Services;

use ArraySubs\Features\PlanSwitching\Services\PlanManager;

defined('ABSPATH') || exit;

/**
 * PlanSwitching hooks integration
 */
class Hooks
{
    /**
     * Enable auto-loading via AbstractLoader
     *
     * @var bool
     */
    public static $loadable = true;

    /**
     * Constructor - Register hooks
     */
    public function __construct()
    {
        // Add upgrade/downgrade fields to WooCommerce Linked Products tab
        add_action('woocommerce_product_options_related', [$this, 'addSwitchingFields']);

        // Save upgrade/downgrade fields
        add_action('woocommerce_process_product_meta', [$this, 'saveSwitchingFields']);

        // Also support variations
        add_action('woocommerce_product_after_variable_attributes', [$this, 'addVariationSwitchingFields'], 10, 3);
        add_action('woocommerce_save_product_variation', [$this, 'saveVariationSwitchingFields'], 10, 2);

        // Hook into subscription status change for plan switch completion
        add_action('arraysubs_plan_switch_completed', [$this, 'onPlanSwitchCompleted'], 10, 4);

        // Add plan switch tracking to subscription updates
        add_action('arraysubs_data_updated_via_api', [$this, 'trackProductChange'], 10, 2);

        // Handle proration order payment
        add_action('woocommerce_payment_complete', [$this, 'onProrationOrderPaid']);
        add_action('woocommerce_order_status_completed', [$this, 'onProrationOrderPaid']);
        add_action('woocommerce_order_status_processing', [$this, 'onProrationOrderPaid']);
    }

    /**
     * Add upgrade/downgrade fields to Linked Products tab
     */
    public function addSwitchingFields(): void
    {
        global $post;

        if (!$post || $post->post_type !== 'product') {
            return;
        }

        // Check if this is a subscription product
        $is_subscription = get_post_meta($post->ID, '_is_subscription', true) === 'yes';

        // Get saved values from database
        $upgrade_products_raw = get_post_meta($post->ID, '_arraysubs_upgrade_products', true);
        $downgrade_products_raw = get_post_meta($post->ID, '_arraysubs_downgrade_products', true);

        // Convert to integer arrays - handle various stored formats
        $upgrade_products = [];
        if (!empty($upgrade_products_raw) && is_array($upgrade_products_raw)) {
            $upgrade_products = array_map('intval', array_values($upgrade_products_raw));
        }

        $downgrade_products = [];
        if (!empty($downgrade_products_raw) && is_array($downgrade_products_raw)) {
            $downgrade_products = array_map('intval', array_values($downgrade_products_raw));
        }

        $crossgrade_products_raw = get_post_meta($post->ID, '_arraysubs_crossgrade_products', true);
        $crossgrade_products = [];
        if (!empty($crossgrade_products_raw) && is_array($crossgrade_products_raw)) {
            $crossgrade_products = array_map('intval', array_values($crossgrade_products_raw));
        }

        $auto_downgrade_product = absint(get_post_meta($post->ID, '_arraysubs_auto_downgrade_product', true));

?>
        <div class="options_group arraysubs-plan-switching" style="<?php echo $is_subscription ? '' : 'display:none;'; ?>">
            <p class="form-field"><strong><?php esc_html_e('Subscription Plan Switching', 'arraysubs'); ?></strong></p>

            <div class="show_if_simple">
                <p class="form-field _arraysubs_upgrade_products_field">
                    <label for="_arraysubs_upgrade_products"><?php esc_html_e('Upgrade to', 'arraysubs'); ?></label>
                    <select
                        id="_arraysubs_upgrade_products"
                        name="_arraysubs_upgrade_products[]"
                        class="wc-product-search"
                        multiple="multiple"
                        style="width: 50%;"
                        data-placeholder="<?php esc_attr_e('Search for products...', 'arraysubs'); ?>"
                        data-action="woocommerce_json_search_products_and_variations"
                        data-exclude="<?php echo intval($post->ID); ?>">
                        <?php
                        foreach ($upgrade_products as $product_id) {
                            $product = wc_get_product($product_id);
                            if ($product) {
                                echo '<option value="' . esc_attr($product_id) . '" selected="selected">' . esc_html(wp_strip_all_tags($product->get_formatted_name())) . '</option>';
                            }
                        }
                        ?>
                    </select>
                    <?php $this->renderSimpleFieldDescription(__('Select products that customers can upgrade to. Upgrades are higher-priced plans. A prorated order is created for the price difference.', 'arraysubs')); ?>
                </p>

                <p class="form-field _arraysubs_downgrade_products_field">
                    <label for="_arraysubs_downgrade_products"><?php esc_html_e('Downgrade to', 'arraysubs'); ?></label>
                    <select
                        id="_arraysubs_downgrade_products"
                        name="_arraysubs_downgrade_products[]"
                        class="wc-product-search"
                        multiple="multiple"
                        style="width: 50%;"
                        data-placeholder="<?php esc_attr_e('Search for products...', 'arraysubs'); ?>"
                        data-action="woocommerce_json_search_products_and_variations"
                        data-exclude="<?php echo intval($post->ID); ?>">
                        <?php
                        foreach ($downgrade_products as $product_id) {
                            $product = wc_get_product($product_id);
                            if ($product) {
                                echo '<option value="' . esc_attr($product_id) . '" selected="selected">' . esc_html(wp_strip_all_tags($product->get_formatted_name())) . '</option>';
                            }
                        }
                        ?>
                    </select>
                    <?php $this->renderSimpleFieldDescription(__('Select products that customers can downgrade to. Downgrades are lower-priced plans. The customer may receive store credit for the remaining balance.', 'arraysubs')); ?>
                </p>

                <p class="form-field _arraysubs_crossgrade_products_field">
                    <label for="_arraysubs_crossgrade_products"><?php esc_html_e('Crossgrade to', 'arraysubs'); ?></label>
                    <select
                        id="_arraysubs_crossgrade_products"
                        name="_arraysubs_crossgrade_products[]"
                        class="wc-product-search"
                        multiple="multiple"
                        style="width: 50%;"
                        data-placeholder="<?php esc_attr_e('Search for products...', 'arraysubs'); ?>"
                        data-action="woocommerce_json_search_products_and_variations"
                        data-exclude="<?php echo intval($post->ID); ?>">
                        <?php
                        foreach ($crossgrade_products as $product_id) {
                            $product = wc_get_product($product_id);
                            if ($product) {
                                echo '<option value="' . esc_attr($product_id) . '" selected="selected">' . esc_html(wp_strip_all_tags($product->get_formatted_name())) . '</option>';
                            }
                        }
                        ?>
                    </select>
                    <?php $this->renderSimpleFieldDescription(__('Select products that customers can crossgrade to. Crossgrades are lateral switches between plans of similar value. No proration or credit is applied.', 'arraysubs')); ?>
                </p>

                <p class="form-field _arraysubs_auto_downgrade_product_field">
                    <label for="_arraysubs_auto_downgrade_product"><?php esc_html_e('Auto-downgrade to', 'arraysubs'); ?></label>
                    <select
                        id="_arraysubs_auto_downgrade_product"
                        name="_arraysubs_auto_downgrade_product"
                        class="wc-product-search"
                        style="width: 50%;"
                        data-placeholder="<?php esc_attr_e('Search for a product...', 'arraysubs'); ?>"
                        data-action="woocommerce_json_search_products_and_variations"
                        data-exclude="<?php echo intval($post->ID); ?>">
                        <?php
                        if ($auto_downgrade_product) {
                            $product = wc_get_product($auto_downgrade_product);
                            if ($product) {
                                echo '<option value="' . esc_attr($auto_downgrade_product) . '" selected="selected">' . esc_html(wp_strip_all_tags($product->get_formatted_name())) . '</option>';
                            }
                        }
                        ?>
                    </select>
                    <?php $this->renderSimpleFieldDescription(__('Automatically switch to this product when the subscription expires or is cancelled. Useful for falling back to a free tier. Timing is controlled in Settings → Plan Switching.', 'arraysubs')); ?>
                </p>
            </div>

            <div class="show_if_variable" style="padding: 5px 20px 20px 162px;">
                <div class="notice inline notice-info" style="margin: 0; padding: 12px 15px;">
                    <p style="margin: 0 !important; font-size: 13px;">
                        <?php esc_html_e('This is a variable product. Please configure plan switching options in the Variations tab.', 'arraysubs'); ?>
                    </p>
                </div>
            </div>
        </div>
    <?php
    }

    /**
     * Save upgrade/downgrade fields
     *
     * @param int $post_id Product ID
     */
    public function saveSwitchingFields(int $post_id): void
    {
        // phpcs:disable WordPress.Security.NonceVerification.Missing -- Nonce verified by WooCommerce

        // Skip if autosave or not a valid save action
        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
            return;
        }

        // Verify this is a proper product save (not AJAX, not revision)
        if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) {
            return;
        }

        $old_upgrade     = get_post_meta($post_id, '_arraysubs_upgrade_products', true);
        $old_downgrade   = get_post_meta($post_id, '_arraysubs_downgrade_products', true);
        $old_crossgrade  = get_post_meta($post_id, '_arraysubs_crossgrade_products', true);
        $old_auto_target = get_post_meta($post_id, '_arraysubs_auto_downgrade_product', true);

        // Process upgrade products
        if (isset($_POST['_arraysubs_upgrade_products']) && is_array($_POST['_arraysubs_upgrade_products'])) {
            $upgrade_products = array_map('absint', $_POST['_arraysubs_upgrade_products']);
            $upgrade_products = array_filter($upgrade_products); // Remove zeros
            update_post_meta($post_id, '_arraysubs_upgrade_products', $upgrade_products);
        } elseif (isset($_POST['post_type']) && $_POST['post_type'] === 'product') {
            // Only clear if this is definitely a product save
            update_post_meta($post_id, '_arraysubs_upgrade_products', []);
        }

        // Process downgrade products
        if (isset($_POST['_arraysubs_downgrade_products']) && is_array($_POST['_arraysubs_downgrade_products'])) {
            $downgrade_products = array_map('absint', $_POST['_arraysubs_downgrade_products']);
            $downgrade_products = array_filter($downgrade_products); // Remove zeros
            update_post_meta($post_id, '_arraysubs_downgrade_products', $downgrade_products);
        } elseif (isset($_POST['post_type']) && $_POST['post_type'] === 'product') {
            // Only clear if this is definitely a product save
            update_post_meta($post_id, '_arraysubs_downgrade_products', []);
        }

        // Process crossgrade products
        if (isset($_POST['_arraysubs_crossgrade_products']) && is_array($_POST['_arraysubs_crossgrade_products'])) {
            $crossgrade_products = array_map('absint', $_POST['_arraysubs_crossgrade_products']);
            $crossgrade_products = array_filter($crossgrade_products); // Remove zeros
            update_post_meta($post_id, '_arraysubs_crossgrade_products', $crossgrade_products);
        } elseif (isset($_POST['post_type']) && $_POST['post_type'] === 'product') {
            // Only clear if this is definitely a product save
            update_post_meta($post_id, '_arraysubs_crossgrade_products', []);
        }

        // Process auto-downgrade product
        if (isset($_POST['_arraysubs_auto_downgrade_product'])) {
            $auto_downgrade = absint($_POST['_arraysubs_auto_downgrade_product']);
            update_post_meta($post_id, '_arraysubs_auto_downgrade_product', $auto_downgrade);
        } elseif (isset($_POST['post_type']) && $_POST['post_type'] === 'product') {
            delete_post_meta($post_id, '_arraysubs_auto_downgrade_product');
        }

        $changed = [];

        if ($this->normalizeProductIdArray($old_upgrade) !== $this->normalizeProductIdArray(get_post_meta($post_id, '_arraysubs_upgrade_products', true))) {
            $changed[] = __('upgrade targets', 'arraysubs');
        }

        if ($this->normalizeProductIdArray($old_downgrade) !== $this->normalizeProductIdArray(get_post_meta($post_id, '_arraysubs_downgrade_products', true))) {
            $changed[] = __('downgrade targets', 'arraysubs');
        }

        if ($this->normalizeProductIdArray($old_crossgrade) !== $this->normalizeProductIdArray(get_post_meta($post_id, '_arraysubs_crossgrade_products', true))) {
            $changed[] = __('crossgrade targets', 'arraysubs');
        }

        if ((string) $old_auto_target !== (string) get_post_meta($post_id, '_arraysubs_auto_downgrade_product', true)) {
            $changed[] = __('auto-downgrade target', 'arraysubs');
        }

        if (!empty($changed) && function_exists('arraysubs_add_system_global_note')) {
            $product = wc_get_product($post_id);
            $product_name = $product ? arraysubs_get_subscription_product_name($product) : '#' . $post_id;

            arraysubs_add_system_global_note(
                sprintf(
                    /* translators: 1: product name, 2: changed plan switching field labels. */
                    __('Product settings updated for %1$s: %2$s.', 'arraysubs'),
                    esc_html($product_name),
                    esc_html(implode(', ', $changed))
                ),
                'private',
                'product'
            );
        }
        // phpcs:enable
    }

    /**
     * Add switching fields to product variations
     *
     * @param int      $loop           Variation loop index
     * @param array    $variation_data Variation data
     * @param \WP_Post $variation      Variation post object
     */
    public function addVariationSwitchingFields(int $loop, array $variation_data, \WP_Post $variation): void
    {
        // Check if this variation is a subscription
        $is_subscription = get_post_meta($variation->ID, '_is_subscription', true) === 'yes';

        $upgrade_products = get_post_meta($variation->ID, '_arraysubs_upgrade_products', true) ?: [];
        $downgrade_products = get_post_meta($variation->ID, '_arraysubs_downgrade_products', true) ?: [];
        $crossgrade_products = get_post_meta($variation->ID, '_arraysubs_crossgrade_products', true) ?: [];

        $auto_downgrade_product = absint(get_post_meta($variation->ID, '_arraysubs_auto_downgrade_product', true));

        // Ensure we have arrays
        $upgrade_products = is_array($upgrade_products) ? $upgrade_products : [];
        $downgrade_products = is_array($downgrade_products) ? $downgrade_products : [];
        $crossgrade_products = is_array($crossgrade_products) ? $crossgrade_products : [];

    ?>
        <div class="arraysubs-variation-switching" style="<?php echo $is_subscription ? '' : 'display:none;'; ?>">
            <p class="form-row form-row-full">
                <strong><?php esc_html_e('Plan Switching', 'arraysubs'); ?></strong>
            </p>

            <p class="form-row form-row-full">
                <label for="arraysubs_upgrade_products_<?php echo esc_attr($loop); ?>">
                    <?php esc_html_e('Upgrade to', 'arraysubs'); ?>
                </label>
                <select
                    id="arraysubs_upgrade_products_<?php echo esc_attr($loop); ?>"
                    name="arraysubs_variation_upgrade_products[<?php echo esc_attr($loop); ?>][]"
                    class="wc-product-search"
                    multiple="multiple"
                    style="width: 100%;"
                    data-placeholder="<?php esc_attr_e('Search for products...', 'arraysubs'); ?>"
                    data-action="woocommerce_json_search_products_and_variations"
                    data-exclude="<?php echo intval($variation->ID); ?>">
                    <?php
                    foreach ($upgrade_products as $product_id) {
                        $product = wc_get_product($product_id);
                        if ($product) {
                            echo '<option value="' . esc_attr($product_id) . '" selected="selected">' . esc_html(wp_strip_all_tags($product->get_formatted_name())) . '</option>';
                        }
                    }
                    ?>
                </select>
                <?php $this->renderVariationFieldDescription(__('Select products that customers can upgrade to. Upgrades are higher-priced plans. A prorated order is created for the price difference.', 'arraysubs')); ?>
            </p>

            <p class="form-row form-row-full">
                <label for="arraysubs_downgrade_products_<?php echo esc_attr($loop); ?>">
                    <?php esc_html_e('Downgrade to', 'arraysubs'); ?>
                </label>
                <select
                    id="arraysubs_downgrade_products_<?php echo esc_attr($loop); ?>"
                    name="arraysubs_variation_downgrade_products[<?php echo esc_attr($loop); ?>][]"
                    class="wc-product-search"
                    multiple="multiple"
                    style="width: 100%;"
                    data-placeholder="<?php esc_attr_e('Search for products...', 'arraysubs'); ?>"
                    data-action="woocommerce_json_search_products_and_variations"
                    data-exclude="<?php echo intval($variation->ID); ?>">
                    <?php
                    foreach ($downgrade_products as $product_id) {
                        $product = wc_get_product($product_id);
                        if ($product) {
                            echo '<option value="' . esc_attr($product_id) . '" selected="selected">' . esc_html(wp_strip_all_tags($product->get_formatted_name())) . '</option>';
                        }
                    }
                    ?>
                </select>
                <?php $this->renderVariationFieldDescription(__('Select products that customers can downgrade to. Downgrades are lower-priced plans. The customer may receive store credit for the remaining balance.', 'arraysubs')); ?>
            </p>

            <p class="form-row form-row-full">
                <label for="arraysubs_crossgrade_products_<?php echo esc_attr($loop); ?>">
                    <?php esc_html_e('Crossgrade to', 'arraysubs'); ?>
                </label>
                <select
                    id="arraysubs_crossgrade_products_<?php echo esc_attr($loop); ?>"
                    name="arraysubs_variation_crossgrade_products[<?php echo esc_attr($loop); ?>][]"
                    class="wc-product-search"
                    multiple="multiple"
                    style="width: 100%;"
                    data-placeholder="<?php esc_attr_e('Search for products...', 'arraysubs'); ?>"
                    data-action="woocommerce_json_search_products_and_variations"
                    data-exclude="<?php echo intval($variation->ID); ?>">
                    <?php
                    foreach ($crossgrade_products as $product_id) {
                        $product = wc_get_product($product_id);
                        if ($product) {
                            echo '<option value="' . esc_attr($product_id) . '" selected="selected">' . esc_html(wp_strip_all_tags($product->get_formatted_name())) . '</option>';
                        }
                    }
                    ?>
                </select>
                <?php $this->renderVariationFieldDescription(__('Select products that customers can crossgrade to. Crossgrades are lateral switches between plans of similar value. No proration or credit is applied.', 'arraysubs')); ?>
            </p>

            <p class="form-row form-row-full">
                <label for="arraysubs_auto_downgrade_product_<?php echo esc_attr($loop); ?>">
                    <?php esc_html_e('Auto-downgrade to', 'arraysubs'); ?>
                </label>
                <select
                    id="arraysubs_auto_downgrade_product_<?php echo esc_attr($loop); ?>"
                    name="arraysubs_variation_auto_downgrade_product[<?php echo esc_attr($loop); ?>]"
                    class="wc-product-search"
                    style="width: 100%;"
                    data-placeholder="<?php esc_attr_e('Search for a product...', 'arraysubs'); ?>"
                    data-action="woocommerce_json_search_products_and_variations"
                    data-exclude="<?php echo intval($variation->ID); ?>">
                    <?php
                    if ($auto_downgrade_product) {
                        $product = wc_get_product($auto_downgrade_product);
                        if ($product) {
                            echo '<option value="' . esc_attr($auto_downgrade_product) . '" selected="selected">' . esc_html(wp_strip_all_tags($product->get_formatted_name())) . '</option>';
                        }
                    }
                    ?>
                </select>
                <?php $this->renderVariationFieldDescription(__('Automatically switch to this product when the subscription expires or is cancelled. Useful for falling back to a free tier. Timing is controlled in Settings → Plan Switching.', 'arraysubs')); ?>
            </p>
        </div>
<?php
    }

    /**
     * Render block help text under a simple product field.
     *
     * @param string $description Help text.
     */
    private function renderSimpleFieldDescription(string $description): void
    {
        printf(
            '<span class="description arraysubs-custom-helptext">%s</span>',
            esc_html($description)
        );
    }

    /**
     * Render block help text under a variation field.
     *
     * @param string $description Help text.
     */
    private function renderVariationFieldDescription(string $description): void
    {
        printf(
            '<span class="description arraysubs-custom-helptext">%s</span>',
            esc_html($description)
        );
    }

    /**
     * Save variation switching fields
     *
     * @param int $variation_id Variation ID
     * @param int $loop         Loop index
     */
    public function saveVariationSwitchingFields(int $variation_id, int $loop): void
    {
        // phpcs:disable WordPress.Security.NonceVerification.Missing -- Nonce verified by WooCommerce
        $old_upgrade     = get_post_meta($variation_id, '_arraysubs_upgrade_products', true);
        $old_downgrade   = get_post_meta($variation_id, '_arraysubs_downgrade_products', true);
        $old_crossgrade  = get_post_meta($variation_id, '_arraysubs_crossgrade_products', true);
        $old_auto_target = get_post_meta($variation_id, '_arraysubs_auto_downgrade_product', true);

        if (isset($_POST['arraysubs_variation_upgrade_products'][$loop])) {
            $upgrade_products = array_map('absint', (array) $_POST['arraysubs_variation_upgrade_products'][$loop]);
            $upgrade_products = array_filter($upgrade_products);
            update_post_meta($variation_id, '_arraysubs_upgrade_products', $upgrade_products);
        } else {
            delete_post_meta($variation_id, '_arraysubs_upgrade_products');
        }

        if (isset($_POST['arraysubs_variation_downgrade_products'][$loop])) {
            $downgrade_products = array_map('absint', (array) $_POST['arraysubs_variation_downgrade_products'][$loop]);
            $downgrade_products = array_filter($downgrade_products);
            update_post_meta($variation_id, '_arraysubs_downgrade_products', $downgrade_products);
        } else {
            delete_post_meta($variation_id, '_arraysubs_downgrade_products');
        }

        if (isset($_POST['arraysubs_variation_crossgrade_products'][$loop])) {
            $crossgrade_products = array_map('absint', (array) $_POST['arraysubs_variation_crossgrade_products'][$loop]);
            $crossgrade_products = array_filter($crossgrade_products);
            update_post_meta($variation_id, '_arraysubs_crossgrade_products', $crossgrade_products);
        } else {
            delete_post_meta($variation_id, '_arraysubs_crossgrade_products');
        }

        if (isset($_POST['arraysubs_variation_auto_downgrade_product'][$loop])) {
            $auto_downgrade = absint($_POST['arraysubs_variation_auto_downgrade_product'][$loop]);
            update_post_meta($variation_id, '_arraysubs_auto_downgrade_product', $auto_downgrade);
        } else {
            delete_post_meta($variation_id, '_arraysubs_auto_downgrade_product');
        }

        $changed = [];

        if ($this->normalizeProductIdArray($old_upgrade) !== $this->normalizeProductIdArray(get_post_meta($variation_id, '_arraysubs_upgrade_products', true))) {
            $changed[] = __('upgrade targets', 'arraysubs');
        }

        if ($this->normalizeProductIdArray($old_downgrade) !== $this->normalizeProductIdArray(get_post_meta($variation_id, '_arraysubs_downgrade_products', true))) {
            $changed[] = __('downgrade targets', 'arraysubs');
        }

        if ($this->normalizeProductIdArray($old_crossgrade) !== $this->normalizeProductIdArray(get_post_meta($variation_id, '_arraysubs_crossgrade_products', true))) {
            $changed[] = __('crossgrade targets', 'arraysubs');
        }

        if ((string) $old_auto_target !== (string) get_post_meta($variation_id, '_arraysubs_auto_downgrade_product', true)) {
            $changed[] = __('auto-downgrade target', 'arraysubs');
        }

        if (!empty($changed) && function_exists('arraysubs_add_system_global_note')) {
            $product = wc_get_product($variation_id);
            $product_name = $product ? arraysubs_get_subscription_product_name($product) : '#' . $variation_id;

            arraysubs_add_system_global_note(
                sprintf(
                    /* translators: 1: variation name, 2: changed plan switching field labels. */
                    __('Product settings updated for variation %1$s: %2$s.', 'arraysubs'),
                    esc_html($product_name),
                    esc_html(implode(', ', $changed))
                ),
                'private',
                'product'
            );
        }
        // phpcs:enable
    }

    /**
     * Normalize a stored product ID collection for comparisons.
     *
     * @param mixed $value Raw stored value.
     * @return int[]
     */
    private function normalizeProductIdArray($value): array
    {
        if (!is_array($value)) {
            return [];
        }

        $value = array_map('absint', $value);
        $value = array_values(array_filter($value));
        sort($value);

        return $value;
    }

    /**
     * Handle plan switch completion
     *
     * @param int    $subscription_id  Subscription ID
     * @param int    $old_product_id   Old product ID
     * @param int    $new_product_id   New product ID
     * @param string $switch_type      'upgrade', 'downgrade', or 'crossgrade'
     */
    public function onPlanSwitchCompleted(int $subscription_id, int $old_product_id, int $new_product_id, string $switch_type): void
    {
        if ($switch_type === 'auto_downgrade') {
            return;
        }

        // Store plan switch history
        $switch_history = get_post_meta($subscription_id, '_plan_switch_history', true) ?: [];

        $switch_history[] = [
            'date' => current_time('mysql', true),
            'old_product_id' => $old_product_id,
            'new_product_id' => $new_product_id,
            'type' => $switch_type,
        ];

        update_post_meta($subscription_id, '_plan_switch_history', $switch_history);

        // Add subscription note
        if (function_exists('arraysubs_add_subscription_note')) {
            $old_product = wc_get_product($old_product_id);
            $new_product = wc_get_product($new_product_id);

            $note = sprintf(
                /* translators: 1: switch type, 2: old product name, 3: new product name */
                __('Plan %1$s: %2$s → %3$s', 'arraysubs'),
                $switch_type,
                $old_product ? arraysubs_get_subscription_product_name($old_product) : '#' . $old_product_id,
                $new_product ? arraysubs_get_subscription_product_name($new_product) : '#' . $new_product_id
            );

            arraysubs_add_subscription_note($subscription_id, $note, 'private', 0, [], 'subscription');
        }

        // Fire action for email notifications
        do_action('arraysubs_send_plan_switch_email', $subscription_id, $switch_type, $old_product_id, $new_product_id);
    }

    /**
     * Handle proration order payment to finalize plan switch
     *
     * @param int $order_id Order ID
     */
    public function onProrationOrderPaid(int $order_id): void
    {
        $order = wc_get_order($order_id);
        if (!$order) {
            return;
        }

        // Check if this is a plan switch proration order
        $order_type = $order->get_meta('_arraysubs_order_type');
        if ($order_type !== 'plan_switch') {
            return;
        }

        // Check if already processed (to avoid double processing)
        if ($order->get_meta('_arraysubs_switch_processed') === 'yes') {
            return;
        }

        $subscription_id = absint($order->get_meta('_arraysubs_subscription_id'));
        $proration_data = $order->get_meta('_arraysubs_proration_data');
        $new_product_id = absint($order->get_meta('_arraysubs_new_product_id'));
        $quantity = absint($order->get_meta('_arraysubs_switch_quantity')) ?: 1;

        if (!$subscription_id || empty($proration_data) || !$new_product_id) {
            return;
        }

        // Update subscription
        $result = PlanManager::updateSubscriptionProduct($subscription_id, $new_product_id, $proration_data, $quantity);

        if (!is_wp_error($result)) {
            // Mark as processed
            $order->update_meta_data('_arraysubs_switch_processed', 'yes');
            $order->save();

            $order->add_order_note(__('Subscription updated after proration payment.', 'arraysubs'));
        } else {
            $order->add_order_note(sprintf(
                /* translators: %s: error message */
                __('Failed to update subscription: %s', 'arraysubs'),
                $result->get_error_message()
            ));
        }
    }

    /**
     * Track product changes made via API update
     *
     * @param int   $subscription_id Subscription ID
     * @param array $updates         Update data
     */
    public function trackProductChange(int $subscription_id, array $updates): void
    {
        // Check if product was changed
        if (!isset($updates['product_id']) && !isset($updates['variation_id'])) {
            return;
        }

        // Get old product info from subscription
        $old_product_id = get_post_meta($subscription_id, '_product_id', true);
        $old_variation_id = get_post_meta($subscription_id, '_variation_id', true);

        // Determine old and new products
        $old_item_id = $old_variation_id ?: $old_product_id;
        $new_item_id = ($updates['variation_id'] ?? 0) ?: ($updates['product_id'] ?? 0);

        // Skip if no change
        if (absint($old_item_id) === absint($new_item_id)) {
            return;
        }

        // Determine switch type by comparing prices
        $switch_type = ProrationCalculator::determineSwitchType(
            absint($old_item_id),
            absint($new_item_id)
        );

        // Fire plan switch action
        do_action(
            'arraysubs_plan_switch_completed',
            $subscription_id,
            absint($old_item_id),
            absint($new_item_id),
            $switch_type
        );
    }
}
