<?php
if (!defined('ABSPATH')) exit;

/**
 * Schedule fallback check every 15 minutes
 */
add_action('init', function () {
    if (!wp_next_scheduled('stakmv_auction_fallback_cron')) {
        wp_schedule_event(time(), 'quarterhour', 'stakmv_auction_fallback_cron');
    }
});

/**
 * Custom schedule
 */
add_filter('cron_schedules', function ($schedules) {
    $schedules['quarterhour'] = [
        'interval' => 900,
        'display'  => 'Every 15 Minutes',
    ];
    return $schedules;
});

/**
 * Promote next highest bidder if winner fails to pay
 */
add_action('stakmv_auction_fallback_cron', function () {
    if (function_exists('stakmv_auctions_enabled') && !stakmv_auctions_enabled()) {
        return;
    }

    global $wpdb;

    // Get unpaid auction orders past deadline.
    // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Auction recovery relies on keyed order meta lookup.
    $orders = wc_get_orders([
        'status'     => ['pending', 'on-hold'],
        'limit'      => -1,
        'meta_key'   => '_stakmv_auction_id',
    ]);
    // phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_meta_key

    foreach ($orders as $order) {

        $auction_id = $order->get_meta('_stakmv_auction_id');
        if (!$auction_id) continue;

        $deadline = (int) $order->get_meta('_stakmv_auction_payment_deadline');
        if (!$deadline || time() < $deadline) continue;

        // Cancel failed order
        $failed_user = $order->get_user_id();
        $order->update_status(
            'cancelled',
            'Auction payment window expired.'
        );

        // Mark failed bidder
        add_post_meta($auction_id, '_stakmv_auction_failed_bidder', $failed_user);

        $failure_action = function_exists('stakmv_auction_failure_action')
            ? stakmv_auction_failure_action($auction_id)
            : 'next_bidder';

        if ($failure_action === 'reopen') {
            $reopen_hours = (int) apply_filters('stakmv_auction_reopen_duration_hours', 24, $auction_id, $order->get_id());
            $reopen_hours = max(1, $reopen_hours);

            update_post_meta($auction_id, '_stakmv_auction_end_time', gmdate('Y-m-d H:i:s', time() + ($reopen_hours * HOUR_IN_SECONDS)));
            update_post_meta($auction_id, '_stakmv_auction_status', 'active');
            continue;
        }

        // Find next eligible bidder
        $failed = get_post_meta($auction_id, '_stakmv_auction_failed_bidder');
        $failed_ids = array_map('intval', array_filter((array) $failed, 'is_numeric'));

        $candidates_cache_key = 'stakmv_fallback_candidates_' . (int) $auction_id;
        $candidates = wp_cache_get($candidates_cache_key, 'stakmv_auctions');
        if (false === $candidates) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Required to resolve fallback winner from bid history table.
            $candidates = $wpdb->get_results(
                // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Dynamic table name uses current site prefix.
                $wpdb->prepare(
                    // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Dynamic table name uses current site prefix.
                    "SELECT * FROM {$wpdb->prefix}stakmv_auction_bids\n                     WHERE auction_id = %d\n                     ORDER BY bid_amount DESC, created_at ASC\n                     LIMIT 50",
                    $auction_id
                )
            );
            wp_cache_set($candidates_cache_key, $candidates, 'stakmv_auctions', MINUTE_IN_SECONDS);
        }
        $next = null;
        if ( is_array( $candidates ) ) {
            foreach ( $candidates as $candidate ) {
                $candidate_user_id = isset( $candidate->user_id ) ? (int) $candidate->user_id : 0;
                if ( $candidate_user_id > 0 && ! in_array( $candidate_user_id, $failed_ids, true ) ) {
                    $next = $candidate;
                    break;
                }
            }
        }

        if (!$next) {
            // No bidders left → close auction
            update_post_meta($auction_id, '_stakmv_auction_status', 'ended');
            continue;
        }

        $product = wc_get_product($auction_id);
        if (!$product) continue;

        // Create order for next bidder
        $new_order = wc_create_order([
            'customer_id' => $next->user_id,
        ]);

        $new_order->add_product($product, 1, [
            'subtotal' => $next->bid_amount,
            'total'    => $next->bid_amount,
        ]);

        $shipping_cost = (float) get_post_meta($auction_id, '_stakmv_auction_shipping_cost', true);
        if ($shipping_cost > 0) {
            $new_order->add_fee([
                'name'   => 'Shipping',
                'amount' => $shipping_cost,
            ]);
        }

        $payment_timeout_hours = function_exists('stakmv_auction_payment_timeout_hours')
            ? stakmv_auction_payment_timeout_hours($auction_id)
            : 48;
        $payment_timeout_hours = max(1, (int) $payment_timeout_hours);

        $new_order->update_meta_data('_stakmv_auction_id', $auction_id);
        $new_order->update_meta_data('_stakmv_auction_payment_deadline', time() + ($payment_timeout_hours * HOUR_IN_SECONDS));

        $new_order->set_status('pending', 'Promoted to winner – awaiting payment');
        $new_order->calculate_totals();
        $new_order->save();

        // Auction still pending payment
        update_post_meta($auction_id, '_stakmv_auction_status', 'pending_payment');
    }
});
