<?php
/**
 * Zoho CRM Scheduled Sync Handler
 *
 * Manages WP-Cron based scheduled sync of WordPress data to Zoho CRM.
 *
 * @package HVACCommunityEvents
 */

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

/**
 * Scheduled Sync Class
 */
class HVAC_Zoho_Scheduled_Sync {
    
    /**
     * Instance of this class
     *
     * @var HVAC_Zoho_Scheduled_Sync
     */
    private static $instance = null;
    
    /**
     * Cron hook name
     */
    const CRON_HOOK = 'hvac_zoho_scheduled_sync';
    
    /**
     * Option names
     */
    const OPTION_ENABLED = 'hvac_zoho_auto_sync';
    const OPTION_INTERVAL = 'hvac_zoho_sync_frequency';
    const OPTION_LAST_SYNC = 'hvac_zoho_last_sync_time';
    const OPTION_LAST_RESULT = 'hvac_zoho_last_sync_result';
    
    /**
     * Get instance of this class
     *
     * @return HVAC_Zoho_Scheduled_Sync
     */
    public static function instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    /**
     * Constructor
     */
    private function __construct() {
        // Register custom cron schedules
        add_filter('cron_schedules', array($this, 'register_cron_schedules'));
        
        // Register the cron action
        add_action(self::CRON_HOOK, array($this, 'run_scheduled_sync'));
        
        // Check if we need to reschedule on settings change
        // Hook into both add_option (first time) and update_option (subsequent changes)
        add_action('add_option_' . self::OPTION_ENABLED, array($this, 'on_setting_added'), 10, 2);
        add_action('update_option_' . self::OPTION_ENABLED, array($this, 'on_setting_change'), 10, 2);
        add_action('update_option_' . self::OPTION_INTERVAL, array($this, 'on_interval_change'), 10, 2);
    }
    
    /**
     * Register custom cron schedules
     *
     * @param array $schedules Existing schedules
     * @return array Modified schedules
     */
    public function register_cron_schedules($schedules) {
        $schedules['every_5_minutes'] = array(
            'interval' => 5 * MINUTE_IN_SECONDS,
            'display' => __('Every 5 Minutes', 'hvac-community-events')
        );
        
        $schedules['every_15_minutes'] = array(
            'interval' => 15 * MINUTE_IN_SECONDS,
            'display' => __('Every 15 Minutes', 'hvac-community-events')
        );
        
        $schedules['every_30_minutes'] = array(
            'interval' => 30 * MINUTE_IN_SECONDS,
            'display' => __('Every 30 Minutes', 'hvac-community-events')
        );
        
        $schedules['every_6_hours'] = array(
            'interval' => 6 * HOUR_IN_SECONDS,
            'display' => __('Every 6 Hours', 'hvac-community-events')
        );
        
        return $schedules;
    }
    
    /**
     * Schedule the sync cron event
     *
     * @param string|null $interval Optional interval override
     * @return bool True if scheduled successfully
     */
    public function schedule_sync($interval = null) {
        // Unschedule any existing event first
        $this->unschedule_sync();
        
        // Get interval from option if not provided
        if (null === $interval) {
            $interval = get_option(self::OPTION_INTERVAL, 'every_5_minutes');
        }
        
        // Schedule the event
        $result = wp_schedule_event(time(), $interval, self::CRON_HOOK);
        
        if ($result !== false) {
            if (class_exists('HVAC_Logger')) {
                HVAC_Logger::info("Scheduled Zoho sync with interval: {$interval}", 'ZohoScheduledSync');
            }
            return true;
        }
        
        return false;
    }
    
    /**
     * Unschedule the sync cron event
     *
     * @return bool True if unscheduled successfully
     */
    public function unschedule_sync() {
        $timestamp = wp_next_scheduled(self::CRON_HOOK);
        
        if ($timestamp) {
            wp_unschedule_event($timestamp, self::CRON_HOOK);
            
            if (class_exists('HVAC_Logger')) {
                HVAC_Logger::info('Unscheduled Zoho sync', 'ZohoScheduledSync');
            }
            return true;
        }
        
        return false;
    }
    
    /**
     * Check if sync is currently scheduled
     *
     * @return bool
     */
    public function is_scheduled() {
        return wp_next_scheduled(self::CRON_HOOK) !== false;
    }
    
    /**
     * Get next scheduled sync time
     *
     * @return int|false Timestamp or false if not scheduled
     */
    public function get_next_scheduled() {
        return wp_next_scheduled(self::CRON_HOOK);
    }
    
    /**
     * Handle first-time option creation
     *
     * @param string $option Option name
     * @param mixed $value Option value
     */
    public function on_setting_added($option, $value) {
        if ($value === '1' || $value === 1 || $value === true) {
            $this->schedule_sync();
        }
    }

    /**
     * Handle setting enabled/disabled change
     *
     * @param mixed $old_value Old option value
     * @param mixed $new_value New option value
     */
    public function on_setting_change($old_value, $new_value) {
        if ($new_value === '1' || $new_value === 1 || $new_value === true) {
            $this->schedule_sync();
        } else {
            $this->unschedule_sync();
        }
    }
    
    /**
     * Handle interval change
     *
     * @param mixed $old_value Old interval value
     * @param mixed $new_value New interval value
     */
    public function on_interval_change($old_value, $new_value) {
        // Only reschedule if currently enabled
        if (get_option(self::OPTION_ENABLED) === '1') {
            $this->schedule_sync($new_value);
        }
    }
    
    /**
     * Run the scheduled sync
     *
     * This is the main cron callback that syncs all data types.
     */
    public function run_scheduled_sync() {
        $start_time = time();
        
        if (class_exists('HVAC_Logger')) {
            HVAC_Logger::info('Starting scheduled Zoho sync', 'ZohoScheduledSync');
        }
        
        // Get last sync time for incremental sync
        $last_sync = $this->get_last_sync_time();
        
        // Initialize results
        $results = array(
            'started_at' => date('Y-m-d H:i:s', $start_time),
            'last_sync_from' => $last_sync ? date('Y-m-d H:i:s', $last_sync) : 'Never',
            'events' => null,
            'users' => null,
            'attendees' => null,
            'rsvps' => null,
            'purchases' => null,
            'errors' => array(),
        );
        
        try {
            // Load dependencies
            require_once HVAC_PLUGIN_DIR . 'includes/zoho/class-zoho-sync.php';
            $sync = new HVAC_Zoho_Sync();
            
            // Sync each type with since_timestamp for incremental sync
            // Events
            $results['events'] = $this->sync_all_batches($sync, 'sync_events', $last_sync);
            
            // Users/Trainers
            $results['users'] = $this->sync_all_batches($sync, 'sync_users', $last_sync);
            
            // Attendees
            $results['attendees'] = $this->sync_all_batches($sync, 'sync_attendees', $last_sync);
            
            // RSVPs
            $results['rsvps'] = $this->sync_all_batches($sync, 'sync_rsvps', $last_sync);
            
            // Purchases/Orders
            $results['purchases'] = $this->sync_all_batches($sync, 'sync_purchases', $last_sync);
            
        } catch (Exception $e) {
            $results['errors'][] = $e->getMessage();
            
            if (class_exists('HVAC_Logger')) {
                HVAC_Logger::error('Scheduled sync error: ' . $e->getMessage(), 'ZohoScheduledSync');
            }
        }
        
        // Update last sync time
        $this->set_last_sync_time($start_time);
        
        // Calculate totals
        $total_synced = 0;
        $total_skipped = 0;
        $total_failed = 0;
        foreach (array('events', 'users', 'attendees', 'rsvps', 'purchases') as $type) {
            if (isset($results[$type]['synced'])) {
                $total_synced += $results[$type]['synced'];
            }
            if (isset($results[$type]['skipped'])) {
                $total_skipped += $results[$type]['skipped'];
            }
            if (isset($results[$type]['failed'])) {
                $total_failed += $results[$type]['failed'];
            }
        }
        
        $results['completed_at'] = date('Y-m-d H:i:s');
        $results['duration_seconds'] = time() - $start_time;
        $results['total_synced'] = $total_synced;
        $results['total_skipped'] = $total_skipped;
        $results['total_failed'] = $total_failed;
        
        // Save last result
        update_option(self::OPTION_LAST_RESULT, $results);
        
        if (class_exists('HVAC_Logger')) {
            HVAC_Logger::info("Scheduled sync completed: {$total_synced} synced, {$total_skipped} skipped, {$total_failed} failed", 'ZohoScheduledSync');
        }
        
        return $results;
    }
    
    /**
     * Sync all batches for a given sync method
     *
     * @param HVAC_Zoho_Sync $sync Sync instance
     * @param string $method Method name (e.g., 'sync_events')
     * @param int|null $since_timestamp Optional timestamp for incremental sync
     * @return array Aggregated results
     */
    private function sync_all_batches($sync, $method, $since_timestamp = null) {
        $offset = 0;
        $limit = 50;
        $aggregated = array(
            'total' => 0,
            'synced' => 0,
            'skipped' => 0,
            'failed' => 0,
            'errors' => array(),
        );
        
        do {
            // Call the sync method with since_timestamp support
            $result = $sync->$method($offset, $limit, $since_timestamp);
            
            // Aggregate results
            $aggregated['total'] = $result['total'] ?? 0;
            $aggregated['synced'] += $result['synced'] ?? 0;
            $aggregated['skipped'] += $result['skipped'] ?? 0;
            $aggregated['failed'] += $result['failed'] ?? 0;
            
            if (!empty($result['errors'])) {
                $aggregated['errors'] = array_merge($aggregated['errors'], $result['errors']);
            }
            
            // Check for more batches
            $has_more = $result['has_more'] ?? false;
            $offset = $result['next_offset'] ?? ($offset + $limit);
            
        } while ($has_more);
        
        return $aggregated;
    }
    
    /**
     * Get the last sync timestamp
     *
     * @return int|null Timestamp or null if never synced
     */
    public function get_last_sync_time() {
        $time = get_option(self::OPTION_LAST_SYNC);
        return $time ? (int) $time : null;
    }
    
    /**
     * Set the last sync timestamp
     *
     * @param int $timestamp Timestamp
     */
    public function set_last_sync_time($timestamp) {
        update_option(self::OPTION_LAST_SYNC, $timestamp);
    }
    
    /**
     * Get the last sync result
     *
     * @return array|null Result array or null
     */
    public function get_last_sync_result() {
        return get_option(self::OPTION_LAST_RESULT);
    }
    
    /**
     * Get sync status summary
     *
     * @return array Status information
     */
    public function get_status() {
        $is_enabled = get_option(self::OPTION_ENABLED) === '1';
        $interval = get_option(self::OPTION_INTERVAL, 'every_5_minutes');
        $last_sync = $this->get_last_sync_time();
        $next_sync = $this->get_next_scheduled();
        $last_result = $this->get_last_sync_result();
        
        return array(
            'enabled' => $is_enabled,
            'interval' => $interval,
            'is_scheduled' => $this->is_scheduled(),
            'last_sync_time' => $last_sync,
            'last_sync_formatted' => $last_sync ? date('Y-m-d H:i:s', $last_sync) : 'Never',
            'next_sync_time' => $next_sync,
            'next_sync_formatted' => $next_sync ? date('Y-m-d H:i:s', $next_sync) : 'Not scheduled',
            'last_result' => $last_result,
        );
    }
    
    /**
     * Run sync manually (for "Run Now" button)
     *
     * @return array Sync results
     */
    public function run_now() {
        return $this->run_scheduled_sync();
    }
}
