<?php
/**
 * Expire old pending/active reservations — run every 5 minutes
 * *\/5 * * * * php /path/cron/expire_reservations.php
 *
 * Also runs the Adaptive Estimation Feedback Loop weekly (Sunday 03:00).
 */
require_once __DIR__ . '/../config.php';
require_once __DIR__ . '/../engine/ReservationEngine.php';
require_once __DIR__ . '/../engine/Logger.php';

Logger::info('expire_cron_start', ['time' => date('c')]);

// ── 1. Expire TTL-expired reservations ────────────────────────
$expired = ReservationEngine::expireOld();

// Enhanced: count by status + alert on high pending
$stats = [];
try {
    $st = db()->query(
        "SELECT status, COUNT(*) cnt, COALESCE(SUM(reserved_sdg),0) total_sdg
         FROM task_reservations GROUP BY status"
    );
    while ($row = $st->fetch()) {
        $stats[$row['status']] = ['count'=>(int)$row['cnt'],'total_sdg'=>(int)$row['total_sdg']];
    }
} catch (Throwable $e) {}

Logger::info('cron_expire_run', [
    'expired'           => $expired,
    'stats'             => $stats,
    'pending_sdg_locked'=> $stats['pending']['total_sdg'] ?? 0,
    'active_sdg_locked' => $stats['active']['total_sdg'] ?? 0,
]);

$pendingCount = $stats['pending']['count'] ?? 0;
if ($pendingCount > 10) {
    Logger::warn('high_pending_reservations', ['count'=>$pendingCount,'sdg'=>$stats['pending']['total_sdg']??0]);
}

// ── 2. Adaptive Feedback Loop (weekly) ───────────────────────
$dayOfWeek = (int)date('w'); // 0 = Sunday
$hour      = (int)date('G');

if ($dayOfWeek === 0 && $hour === 3) {
    adaptiveFeedbackLoop();
}

function adaptiveFeedbackLoop(): void {
    Logger::info('adaptive_feedback_start');

    if (!(bool)PricingEngine::getSetting('adaptive_feedback_enabled', true)) {
        Logger::info('adaptive_feedback_disabled');
        return;
    }

    try {
        // Get task types with enough data (≥ 20 samples)
        $st = db()->query(
            "SELECT
               JSON_UNQUOTE(JSON_EXTRACT(el.value, '$.type')) AS task_type,
               JSON_UNQUOTE(JSON_EXTRACT(el.value, '$.subtype')) AS task_subtype,
               AVG(tel.accuracy_pct) AS avg_accuracy,
               COUNT(*) AS sample_count
             FROM task_estimation_log tel,
                  JSON_TABLE(tel.estimated_plan, '$.tasks[*]' COLUMNS(
                    value JSON PATH '$'
                  )) AS el
             WHERE tel.was_executed=1
               AND tel.accuracy_pct IS NOT NULL
               AND tel.completed_at >= DATE_SUB(NOW(), INTERVAL 90 DAY)
             GROUP BY task_type, task_subtype
             HAVING sample_count >= 20"
        )->fetchAll();

        foreach ($st as $row) {
            $key         = ($row['task_type'] ?? '') . ':' . ($row['task_subtype'] ?? 'standard');
            $avgAccuracy = (float)$row['avg_accuracy'];
            $sampleCount = (int)$row['sample_count'];

            // Compute new multiplier to correct systematic bias
            // If avg_accuracy = 90%, we've been over-estimating by 10%
            // → multiply future estimates by 0.90 to be more accurate
            $newMultiplier = $avgAccuracy > 0 ? round($avgAccuracy / 100, 3) : 1.0;

            // Only update if significantly off (avoid thrashing)
            if (abs($newMultiplier - 1.0) < 0.02) {
                $newMultiplier = 1.0; // snap to 1.0 if within 2%
            }

            db()->prepare(
                "INSERT INTO estimation_multipliers (task_type, multiplier, sample_count, avg_accuracy)
                 VALUES (?, ?, ?, ?)
                 ON DUPLICATE KEY UPDATE
                   multiplier=?, sample_count=?, avg_accuracy=?, updated_at=NOW()"
            )->execute([
                $key, $newMultiplier, $sampleCount, $avgAccuracy,
                $newMultiplier, $sampleCount, $avgAccuracy,
            ]);

            Logger::info('adaptive_multiplier_updated', [
                'type'         => $key,
                'multiplier'   => $newMultiplier,
                'avg_accuracy' => $avgAccuracy,
                'samples'      => $sampleCount,
            ]);
        }

    } catch (Throwable $e) {
        Logger::error('adaptive_feedback_failed', ['error' => $e->getMessage()]);
    }

    Logger::info('adaptive_feedback_complete');
}

echo date('H:i:s') . " — expired: $expired | pending: " . ($stats['pending']['count'] ?? 0) . " | active: " . ($stats['active']['count'] ?? 0) . "\n";
