<?php
declare(strict_types=1);

require __DIR__ . '/app/bootstrap.php';
global $config;

if (PHP_SAPI === 'cli') {
    $args = getopt('', ['token:']);
    $token = (string)($args['token'] ?? '');
} else {
    $token = (string)($_GET['token'] ?? '');
    header('Content-Type: application/json; charset=UTF-8');
}

if ($token === '' || !hash_equals((string)$config['cron_token'], $token)) {
    http_response_code(403);
    echo json_encode(['ok' => false, 'error' => 'Forbidden']);
    exit(1);
}

@set_time_limit(55);
$lockPath = APP_ROOT . '/storage/cron.lock';
$lock = fopen($lockPath, 'c+');
if (!$lock || !flock($lock, LOCK_EX | LOCK_NB)) {
    http_response_code(409);
    echo json_encode(['ok' => false, 'error' => 'Another cron run is active']);
    exit(0);
}

$db = DB::connection();
$db->exec("UPDATE import_queue SET status='pending',available_at=NOW(),updated_at=NOW() WHERE status='processing' AND updated_at<DATE_SUB(NOW(),INTERVAL 30 MINUTE)");
$runStmt = $db->prepare("INSERT INTO cron_runs(started_at,status,created_at) VALUES(NOW(),'running',NOW())");
$runStmt->execute();
$runId = (int)$db->lastInsertId();
$sourceCount = 0;
$found = 0;
$errors = [];

try {
    $importer = new GooglePlayImporter($db);
    $sources = $db->query("SELECT * FROM sources WHERE active=1 AND (next_run_at IS NULL OR next_run_at<=NOW()) ORDER BY priority DESC,next_run_at ASC LIMIT 2")->fetchAll();
    foreach ($sources as $source) {
        $result = $importer->discoverSource($source);
        $sourceCount++;
        $found += (int)$result['found'];
        if (!$result['ok']) {
            $errors[] = $source['name'] . ': ' . $result['error'];
        }
    }

    $stale = $db->query("SELECT package_id,source_id FROM games WHERE status IN ('published','review') AND (last_checked_at IS NULL OR last_checked_at<DATE_SUB(NOW(),INTERVAL 14 DAY)) ORDER BY last_checked_at ASC LIMIT 5")->fetchAll();
    $queueStale = $db->prepare("INSERT INTO import_queue(package_id,source_id,status,priority,attempts,available_at,created_at,updated_at) VALUES(?,?,'pending',20,0,NOW(),NOW(),NOW()) ON DUPLICATE KEY UPDATE status=IF(status='processing',status,'pending'),priority=GREATEST(priority,20),available_at=NOW(),updated_at=NOW()");
    foreach ($stale as $game) {
        $queueStale->execute([$game['package_id'], $game['source_id']]);
    }

    $queue = $importer->processQueue(12);
    $status = ($errors || $queue['failed']) ? 'partial' : 'success';
    $message = $errors ? implode(' | ', $errors) : 'Automation completed';
    $finish = $db->prepare('UPDATE cron_runs SET finished_at=NOW(),status=?,sources_checked=?,urls_found=?,queue_processed=?,imported=?,failed=?,message=? WHERE id=?');
    $finish->execute([$status, $sourceCount, $found, $queue['processed'], $queue['ok'], $queue['failed'], mb_substr($message, 0, 1000), $runId]);

    $db->exec("DELETE FROM cron_runs WHERE created_at<DATE_SUB(NOW(),INTERVAL 180 DAY)");
    $db->exec("DELETE FROM import_queue WHERE status='done' AND updated_at<DATE_SUB(NOW(),INTERVAL 30 DAY)");

    echo json_encode([
        'ok' => $status !== 'failed',
        'status' => $status,
        'sources_checked' => $sourceCount,
        'urls_found' => $found,
        'processed' => $queue['processed'],
        'imported' => $queue['ok'],
        'failed' => $queue['failed'],
    ], JSON_UNESCAPED_SLASHES);
} catch (Throwable $e) {
    $db->prepare("UPDATE cron_runs SET finished_at=NOW(),status='failed',message=? WHERE id=?")->execute([mb_substr($e->getMessage(), 0, 1000), $runId]);
    log_message('CRON', $e->getMessage());
    http_response_code(500);
    echo json_encode(['ok' => false, 'error' => 'Cron failed; see admin activity']);
    exit(1);
} finally {
    flock($lock, LOCK_UN);
    fclose($lock);
}
