<?php

namespace App\Commands;

use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;

/**
 * Single cron entry point, invoked every minute per 10-deployment-guide.md
 * §5: `* * * * * php spark tasks:run`. Internally dispatches to each real
 * task only when its own schedule says it's due, so the crontab itself
 * never needs editing when task frequencies change.
 */
class TasksRun extends BaseCommand
{
    protected $group       = 'Scheduler';
    protected $name        = 'tasks:run';
    protected $description = 'Runs all due scheduled tasks (subscription expiry, credit expiry, notifications, interview reminders, cleanup, reports).';

    public function run(array $params)
    {
        // Marker file consumed by InstallController::verifyCron() so the
        // installer's post-setup self-test can confirm cron is actually firing.
        file_put_contents(WRITEPATH . 'cron_last_run.txt', date('c'));

        $this->runIfDue('subscription:expiry-check', '00:15', 1440);
        $this->runIfDue('credit:expiry-check', '00:30', 1440);
        $this->runIfDue('jobs:expiry-check', '00:45', 1440);
        $this->runIfDue('notifications:digest', null, 15);
        $this->runIfDue('interviews:reminders', null, 30);
        $this->runIfDue('cleanup:temp-files', '03:00', 1440);
        $this->runIfDue('reports:generate', '02:00', 1440);
    }

    /**
     * $timeOfDay (HH:MM) restricts a task to run once within its window
     * daily; $intervalMinutes-only tasks (timeOfDay = null) run whenever
     * that many minutes have elapsed since last run, tracked via a
     * per-task marker file (simplest possible durable "last ran at"
     * store, avoiding a dependency on a queue/lock table for this).
     */
    private function runIfDue(string $commandName, ?string $timeOfDay, int $intervalMinutes): void
    {
        $markerFile = WRITEPATH . 'cron/' . str_replace(':', '_', $commandName) . '.lastrun';
        if (! is_dir(WRITEPATH . 'cron')) {
            mkdir(WRITEPATH . 'cron', 0755, true);
        }

        $lastRun = file_exists($markerFile) ? (int) file_get_contents($markerFile) : 0;
        $now = time();

        if ($timeOfDay !== null) {
            // Once-daily task: due if we've crossed today's HH:MM and
            // haven't run today yet.
            $today = date('Y-m-d');
            $scheduledTimestamp = strtotime("{$today} {$timeOfDay}");
            $alreadyRanToday = date('Y-m-d', $lastRun) === $today;
            if ($now < $scheduledTimestamp || $alreadyRanToday) {
                return;
            }
        } else {
            if (($now - $lastRun) < ($intervalMinutes * 60)) {
                return;
            }
        }

        CLI::write("Running scheduled task: {$commandName}", 'green');
        command($commandName);
        file_put_contents($markerFile, (string) $now);
    }
}
