<?php

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

class AIEO_Fulfillment_Cron {

    const HOOK_POLL          = 'aieo_fulfillment_poll_tick';
    const HOOK_CLOSE_PENDING = 'aieo_fulfillment_close_pending_tick';
    const LOCK_TRANSIENT     = 'aieo_fulfillment_poll_lock';
    const POLL_BATCH         = 200;
    const MIN_POLL_GAP_SEC   = 3000; 

    public static function register() {
        add_action(self::HOOK_POLL,          array(__CLASS__, 'poll_tick'));
        add_action(self::HOOK_CLOSE_PENDING, array(__CLASS__, 'close_pending_tick'));

        if (!wp_next_scheduled(self::HOOK_POLL)) {
            wp_schedule_event(time() + 60, 'hourly', self::HOOK_POLL);
        }
        if (!wp_next_scheduled(self::HOOK_CLOSE_PENDING)) {
            wp_schedule_event(time() + 120, 'daily', self::HOOK_CLOSE_PENDING);
        }
    }

    
    public static function poll_tick() {
        if (!self::feature_in_use()) { return; }
        if (get_transient(self::LOCK_TRANSIENT)) { return; }
        set_transient(self::LOCK_TRANSIENT, 1, 15 * MINUTE_IN_SECONDS);

        try {
            self::poll_inner();
        } catch (\Throwable $e) {
            
            if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log('AIEO Fulfillment poll_tick error: ' . $e->getMessage()); }
        }
        delete_transient(self::LOCK_TRANSIENT);
    }

    private static function poll_inner() {
        global $wpdb;
        $table   = $wpdb->prefix . 'aieo_dmm_fulfillment_vouchers';
        $cutoff  = gmdate('Y-m-d H:i:s', time() - self::MIN_POLL_GAP_SEC);
        $batch   = self::POLL_BATCH;

        
        
        $rows = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM {$table}
                 WHERE status NOT IN ('delivered','returned','canceled','failed')
                   AND (last_polled_at IS NULL OR last_polled_at < %s)
                 ORDER BY (last_polled_at IS NULL) DESC, last_polled_at ASC, id ASC
                 LIMIT %d",
                $cutoff, $batch
            ),
            ARRAY_A
        );
        if (empty($rows)) { return; }

        $module   = self::module();
        if (!$module) { return; }
        $couriers = $module->couriers();

        foreach ($rows as $v) {
            $carrier = (string) $v['carrier'];
            $driver  = isset($couriers[$carrier]) ? $couriers[$carrier] : null;
            if (!$driver || !$driver->has_capability('track')) {
                
                
                AIEO_Fulfillment_Vouchers::update($v['id'], array('last_polled_at' => current_time('mysql', true)));
                continue;
            }

            try {
                $r = $driver->track((string) $v['voucher_no']);
            } catch (\Throwable $e) {
                $r = array('ok' => false, 'error' => 'driver_throw: ' . $e->getMessage());
            }

            if (empty($r['ok'])) {
                
                AIEO_Fulfillment_Vouchers::update($v['id'], array('last_polled_at' => current_time('mysql', true)));
                continue;
            }

            $previous = (string) $v['status'];
            $unified  = $driver->map_status((string) ($r['status_code'] ?? ''));
            $effective = $unified !== 'unknown' ? $unified : $previous;

            AIEO_Fulfillment_Vouchers::update_status(
                (int) $v['id'],
                $effective,
                (string) ($r['status_code'] ?? ''),
                isset($r['delivered_at']) ? $r['delivered_at'] : null,
                isset($r['consignee'])    ? $r['consignee']    : null,
                isset($r['arrived_at'])     ? $r['arrived_at']     : null,
                isset($r['arrived_status']) ? $r['arrived_status'] : null
            );
            if (!empty($r['checkpoints'])) {
                AIEO_Fulfillment_Vouchers::record_checkpoints((int) $v['id'], $r['checkpoints']);
            }

            
            
            if ($effective !== $previous) {
                
                do_action('aieo_fulfillment_voucher_status_changed', AIEO_Fulfillment_Vouchers::get($v['id']), $previous);

                if ($effective === 'delivered') {
                    do_action('aieo_fulfillment_voucher_delivered', AIEO_Fulfillment_Vouchers::get($v['id']), $previous);
                }
            }
        }
    }

    
    public static function close_pending_tick() {
        if (!self::feature_in_use()) { return; }
        
        
        
        
        if (class_exists('AIEO_Fulfillment_Settings')
            && AIEO_Fulfillment_Settings::get('auto_close_enabled', true) === false) {
            return;
        }
        $module = self::module();
        if (!$module) { return; }
        $results = array();
        foreach ($module->couriers() as $code => $driver) {
            try {
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                if (class_exists('AIEO_Fulfillment_Closings')) {
                    $r = AIEO_Fulfillment_Closings::close_and_log($driver, 'cron');
                } elseif ($driver->has_capability('close_pending')) {
                    $r = $driver->close_pending();
                } else {
                    continue; 
                }
                if (!empty($r['skipped'])) { continue; } 
                $results[$code] = !empty($r['ok']) ? 'ok' : ('err: ' . (isset($r['error']) ? $r['error'] : 'unknown'));
            } catch (\Throwable $e) {
                $results[$code] = 'throw: ' . $e->getMessage();
                if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log(sprintf('AIEO Fulfillment close_pending(%s) failed: %s', $code, $e->getMessage())); }
            }
        }
        
        if (class_exists('AIEO_Fulfillment_Settings')) {
            AIEO_Fulfillment_Settings::set_many(array(
                'auto_close_last_run_at'      => current_time('mysql', true),
                'auto_close_last_run_results' => $results,
            ));
        }
    }

    
    private static function feature_in_use() {
        global $wpdb;
        $table = $wpdb->prefix . 'aieo_dmm_fulfillment_vouchers';
        
        if ($wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $table)) !== $table) {
            return false;
        }
        return (int) $wpdb->get_var("SELECT 1 FROM {$table} LIMIT 1") === 1;
    }

    
    private static function module() {
        if (class_exists('AIEO_DMM') && method_exists('AIEO_DMM', 'instance')) {
            $dmm = AIEO_DMM::instance();
            if (method_exists($dmm, 'get_module')) {
                $m = $dmm->get_module('fulfillment');
                if ($m instanceof AIEO_DMM_Fulfillment) { return $m; }
            }
        }
        
        return class_exists('AIEO_DMM_Fulfillment') ? new AIEO_DMM_Fulfillment() : null;
    }
}
