<?php
/**
 * Background Scheduler & WP-Cron Engine
 * Wakes up every 5 minutes to process globally scheduled campaigns and pushes them to the Central API.
 */

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

class PexEmail_Cron {

    public function init() {
        // Register custom 5-minute interval safely
        add_filter( 'cron_schedules', [ $this, 'add_cron_interval' ] );

        // Schedule the event if it doesn't exist
        if ( ! wp_next_scheduled( 'pexemail_cron_worker' ) ) {
            wp_schedule_event( time(), 'pexemail_five_minutes', 'pexemail_cron_worker' );
        }

        // Hook the worker to the scheduled event
        add_action( 'pexemail_cron_worker', [ $this, 'process_scheduled_campaigns' ] );
    }

    public function add_cron_interval( $schedules ) {
        if ( ! is_array( $schedules ) ) {
            $schedules = [];
        }

        $schedules['pexemail_five_minutes'] = [
            'interval' => 300,
            'display'  => esc_html__( 'Every 5 Minutes (Pexally Engine)', 'pexally-email-campaigns' )
        ];
        
        return $schedules;
    }

    public function process_scheduled_campaigns() {
        global $wpdb;

        $columns = $wpdb->get_col( "SHOW COLUMNS FROM {$wpdb->prefix}pexemail_campaigns", 0 );
        if ( empty( $columns ) || ! is_array( $columns ) || ! in_array( 'scheduled_at', $columns, true ) ) {
            return; 
        }

        $now = time(); 

        // Grab campaigns that are scheduled to send NOW or are currently mid-sending
        $campaigns = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}pexemail_campaigns WHERE status IN ('scheduled', 'sending_cron') AND scheduled_at > 0 AND scheduled_at <= %d", $now ) );

        if ( empty( $campaigns ) ) {
            return;
        }

        // Load dependencies dynamically
        require_once PEXEMAIL_DIR . 'includes/class-pexemail-ajax.php';
        require_once PEXEMAIL_DIR . 'includes/class-pexemail-tracking.php';
        
        $ajax_engine = new PexEmail_Ajax();

        // Get Global Configurations
        $settings     = get_option( 'pexemail_settings', [] );
        $license_key  = get_option( 'pexemail_license_key', '' );
        $sender_email = ! empty( $settings['sender_email'] ) ? $settings['sender_email'] : get_option( 'admin_email' );

        foreach ( $campaigns as $campaign ) {
            
            if ( $campaign->status === 'scheduled' ) {
                $wpdb->update( $wpdb->prefix . 'pexemail_campaigns', [ 'status' => 'sending_cron' ], [ 'id' => $campaign->id ], [ '%s' ], [ '%d' ] );
            }

            // We batch 50 at a time to send to the Central API
            $batch_size = 50;
            
            // Quickly grab the IDs of the pending recipients
            $pending_ids = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM {$wpdb->prefix}pexemail_recipients WHERE campaign_id = %d AND status = 'pending' LIMIT %d", $campaign->id, $batch_size ) );

            if ( empty( $pending_ids ) ) {
                $wpdb->update( $wpdb->prefix . 'pexemail_campaigns', [ 'status' => 'completed' ], [ 'id' => $campaign->id ], [ '%s' ], [ '%d' ] );
                continue;
            }

            // Lock these specific recipients in the DB so no other cron worker touches them
            $id_list = implode( ',', array_map( 'intval', $pending_ids ) );
            $wpdb->query( "UPDATE {$wpdb->prefix}pexemail_recipients SET status = 'processing_cron' WHERE id IN ($id_list)" );

            // Fetch the locked rows
            $recipients = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}pexemail_recipients WHERE id IN ($id_list)" );

            // Prepare the template wrapper & dynamic tracking links
            $wrapped_template = $ajax_engine->wrap_email_html( stripslashes( $campaign->template ), stripslashes( $campaign->subject ) );
            
            $cb = time() . wp_rand(100, 999);
            $pixel_url = rest_url("pex-campaign/v1/track/open/{$campaign->id}/{{rec_id}}/{{sec_hash}}?cb={$cb}");
            $tracking_pixel = '<img src="' . esc_url($pixel_url) . '" width="1" height="1" style="display:none; visibility:hidden; mso-hide:all;" alt="" role="presentation" />';
            
            $body = preg_replace_callback('/<a[^>]+href=["\']([^"\']+)["\'][^>]*>/i', function($matches) use($campaign) {
                $original_url = $matches[1];
                if(strpos($original_url, '#') === 0 || strpos($original_url, 'mailto:') === 0) return $matches[0];
                $clean_url = html_entity_decode($original_url, ENT_QUOTES, 'UTF-8');
                $tracked_url = rest_url("pex-campaign/v1/track/click/{$campaign->id}/{{rec_id}}/{{sec_hash}}?cb=" . time() . wp_rand(10,99) . "&url=" . urlencode($clean_url));
                return str_replace($original_url, esc_url($tracked_url), $matches[0]);
            }, $wrapped_template);

            $body .= $tracking_pixel;

            // Prepare API Payload
            $payload_recipients = [];
            foreach ( $recipients as $recipient ) {
                $payload_recipients[] = [
                    'id'         => $recipient->id,
                    'email'      => $recipient->email,
                    'first_name' => $recipient->first_name,
                    'last_name'  => $recipient->last_name,
                    'sec_hash'   => PexEmail_Tracking::generate_tracking_hash( $campaign->id, $recipient->id )
                ];
            }

            $payload = [
                'license_key'   => $license_key,
                'sender_email'  => $sender_email,
                'subject'       => stripslashes( $campaign->subject ),
                'body'          => $body,
                'recipients'    => $payload_recipients,
                'smtp_settings' => $settings
            ];

            // 🚀 Ping the Central Server
            $response = wp_remote_post( 'https://payment.pexally.com/wp-json/pexally-email-engine/v1/queue-campaign', [
                'timeout'     => 15,
                'headers'     => [ 'Content-Type' => 'application/json', 'Accept' => 'application/json' ],
                'body'        => wp_json_encode( $payload ),
            ]);

            $status_code = wp_remote_retrieve_response_code( $response );
            $body_response = json_decode( wp_remote_retrieve_body( $response ), true );

            // If Central Server Rejects (Daily Limit reached, wrong email, network error)
            if ( is_wp_error( $response ) || $status_code === 403 || ( isset( $body_response['success'] ) && $body_response['success'] === false ) ) {
                // Revert recipients back to pending so the Cron tries again later (e.g. tomorrow when limits reset)
                $wpdb->query( "UPDATE {$wpdb->prefix}pexemail_recipients SET status = 'pending' WHERE id IN ($id_list)" );
                continue;
            }

            // Success! The Central Server accepted the payload. Mark as 'sent' locally.
            $wpdb->query( "UPDATE {$wpdb->prefix}pexemail_recipients SET status = 'sent' WHERE id IN ($id_list)" );
        }
    }
}