<?php
/**
 * Teleship Sync Scheduler
 *
 * Wraps WooCommerce Action Scheduler for non-blocking product and order sync.
 * Instead of running bulk sync inline (which blocks the HTTP request), this
 * schedules single-action jobs that run in the background.
 *
 * @package Teleship
 * @since 2.0.0
 */

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

class Teleship_Sync_Scheduler {

    /**
     * Action hook for async product sync
     */
    const PRODUCT_SYNC_HOOK = 'teleship_async_product_sync';

    /**
     * Action hook for async order sync
     */
    const ORDER_SYNC_HOOK = 'teleship_async_order_sync';

    /**
     * Option key for sync status tracking
     */
    const STATUS_OPTION = 'teleship_sync_status';

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

    /**
     * Get singleton instance
     *
     * @return Teleship_Sync_Scheduler
     */
    public static function instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Constructor — registers Action Scheduler callbacks
     */
    private function __construct() {
        add_action(self::PRODUCT_SYNC_HOOK, array($this, 'run_product_sync'));
        add_action(self::ORDER_SYNC_HOOK, array($this, 'run_order_sync'));

        // AJAX handler for polling sync status
        add_action('wp_ajax_teleship_sync_status', array($this, 'ajax_sync_status'));
    }

    /**
     * Initialize scheduler
     */
    public static function init() {
        self::instance();
    }

    /**
     * Schedule both product and order sync as background jobs.
     * Called after OAuth callback completes.
     */
    public function schedule_initial_sync() {
        $this->schedule_product_sync();
        // Delay order sync by 5 seconds to let product sync start first
        $this->schedule_order_sync(5);
    }

    /**
     * Schedule async product sync
     *
     * @param int $delay Seconds to delay before running (default 0).
     */
    public function schedule_product_sync($delay = 0) {
        if (!function_exists('as_has_scheduled_action') || !function_exists('as_schedule_single_action')) {
            teleship_log('[SyncScheduler] Action Scheduler not available, falling back to sync');
            $this->run_product_sync();
            return;
        }

        if (as_has_scheduled_action(self::PRODUCT_SYNC_HOOK)) {
            teleship_log('[SyncScheduler] Product sync already scheduled, skipping');
            return;
        }

        $this->update_status('products', 'pending');

        as_schedule_single_action(time() + $delay, self::PRODUCT_SYNC_HOOK, array(), 'teleship');
        teleship_log('[SyncScheduler] Product sync scheduled (delay=' . $delay . 's)');
    }

    /**
     * Schedule async order sync
     *
     * @param int $delay Seconds to delay before running (default 0).
     */
    public function schedule_order_sync($delay = 0) {
        if (!function_exists('as_has_scheduled_action') || !function_exists('as_schedule_single_action')) {
            teleship_log('[SyncScheduler] Action Scheduler not available, falling back to sync');
            $this->run_order_sync();
            return;
        }

        if (as_has_scheduled_action(self::ORDER_SYNC_HOOK)) {
            teleship_log('[SyncScheduler] Order sync already scheduled, skipping');
            return;
        }

        $this->update_status('orders', 'pending');

        as_schedule_single_action(time() + $delay, self::ORDER_SYNC_HOOK, array(), 'teleship');
        teleship_log('[SyncScheduler] Order sync scheduled (delay=' . $delay . 's)');
    }

    /**
     * Execute product sync (called by Action Scheduler)
     */
    public function run_product_sync() {
        teleship_log('[SyncScheduler] Running async product sync');
        $this->update_status('products', 'running');

        try {
            $product_sync = Teleship_Product_Sync::instance();
            $result = $product_sync->bulk_sync_all_products();

            $this->update_status('products', 'completed', $result);
            teleship_log('[SyncScheduler] Product sync completed: ' . wp_json_encode($result));
        } catch (\Exception $e) {
            $this->update_status('products', 'failed', array('error' => $e->getMessage()));
            teleship_log('[SyncScheduler] Product sync failed: ' . $e->getMessage());
        }
    }

    /**
     * Execute order sync (called by Action Scheduler)
     */
    public function run_order_sync() {
        teleship_log('[SyncScheduler] Running async order sync');
        $this->update_status('orders', 'running');

        try {
            $order_sync = teleship_order_sync();
            $result = $order_sync->bulk_sync();

            $this->update_status('orders', 'completed', $result);
            teleship_log('[SyncScheduler] Order sync completed: ' . wp_json_encode($result));
        } catch (\Exception $e) {
            $this->update_status('orders', 'failed', array('error' => $e->getMessage()));
            teleship_log('[SyncScheduler] Order sync failed: ' . $e->getMessage());
        }
    }

    /**
     * Get current sync status for both products and orders
     *
     * @return array
     */
    public function get_sync_status() {
        $status = get_option(self::STATUS_OPTION, array());

        return array(
            'products' => isset($status['products']) ? $status['products'] : array('status' => 'idle'),
            'orders'   => isset($status['orders'])   ? $status['orders']   : array('status' => 'idle'),
        );
    }

    /**
     * AJAX handler — returns sync status as JSON for frontend polling
     */
    public function ajax_sync_status() {
        check_ajax_referer('teleship_admin_nonce', 'nonce');

        if (!current_user_can('manage_woocommerce')) {
            wp_send_json_error(array('message' => 'Permission denied'));
        }

        wp_send_json_success($this->get_sync_status());
    }

    /**
     * Update sync status for a given type
     *
     * @param string $type   'products' or 'orders'
     * @param string $state  'pending', 'running', 'completed', 'failed'
     * @param array  $data   Optional result data (totals, errors, etc.)
     */
    private function update_status($type, $state, $data = array()) {
        $status = get_option(self::STATUS_OPTION, array());

        $status[$type] = array_merge(
            array(
                'status'     => $state,
                'updated_at' => current_time('mysql'),
            ),
            $data
        );

        update_option(self::STATUS_OPTION, $status, false);

        // Report terminal states to Teleship API
        if (in_array($state, array('completed', 'failed'), true)) {
            $this->report_sync_status_to_teleship();
        }
    }

    /**
     * Report current sync status to Teleship API
     *
     * Pushes the local sync status to the integration metadata
     * via PATCH /api/integrations/:id so the admin dashboard can display progress.
     */
    private function report_sync_status_to_teleship() {
        $integration_id = get_option('teleship_integration_id');
        $account_id     = get_option('teleship_account_id');

        if (empty($integration_id) || empty($account_id)) {
            teleship_log('[SyncScheduler] Cannot report sync status: missing integration_id or account_id');
            return;
        }

        $status = $this->get_sync_status();

        $api_url = teleship_get_api_url() . '/api/integrations/' . $integration_id;

        teleship_log('[SyncScheduler] Reporting sync status to Teleship: ' . $api_url);

        $response = Teleship_HTTP_Client::patch(
            $api_url,
            array(
                'metadata' => array(
                    'syncStatus' => $status,
                ),
            ),
            array(
                'headers' => array(
                    'Authorization' => 'Bearer ' . teleship_oauth()->get_bearer_token(),
                    'x-account-id'  => $account_id,
                ),
                'timeout'  => 15,
                'blocking' => false,
            )
        );

        if (is_wp_error($response)) {
            teleship_log('[SyncScheduler] Failed to report sync status: ' . $response->get_error_message());
        } else {
            teleship_log('[SyncScheduler] Sync status reported successfully');
        }
    }
}

/**
 * Get Teleship Sync Scheduler instance
 *
 * @return Teleship_Sync_Scheduler
 */
function teleship_sync_scheduler() {
    return Teleship_Sync_Scheduler::instance();
}

// Initialize early so Action Scheduler callback hooks are registered
add_action('plugins_loaded', array('Teleship_Sync_Scheduler', 'init'), 15);
