<?php
/**
 * Расчёт «когда расписание запустит модуль в следующий раз» для кабинета.
 * Учитывает: авто-запуск, дату старта, периодичность (каждый день / через N дней),
 * время запуска, окно часов и то, отработал ли модуль уже сегодня по расписанию.
 */

if (!function_exists('sched_val')) {
    function sched_val(PDO $pdo, string $key, string $def = ''): string {
        $st = $pdo->prepare('SELECT value FROM settings WHERE key = ?');
        $st->execute([$key]);
        $v = $st->fetchColumn();
        return ($v === false || $v === null) ? $def : (string)$v;
    }
}

if (!function_exists('sched_parse')) {
    /** Разбор даты из базы: понимает «2026-09-24 06:00:00» и «2026-09-24 06:00». */
    function sched_parse(string $s, DateTimeZone $tz): ?DateTime {
        $s = trim($s);
        if ($s === '') return null;
        // длины строк строго соответствуют форматам: 19 / 16 / 10 символов
        foreach ([['Y-m-d H:i:s', 19], ['Y-m-d H:i', 16], ['Y-m-d', 10]] as [$fmt, $len]) {
            if (strlen($s) < $len) continue;
            $dt = DateTime::createFromFormat($fmt, substr($s, 0, $len), $tz);
            if ($dt instanceof DateTime) return $dt;
        }
        try {
            return new DateTime($s, $tz);     // время трактуем как московское
        } catch (Exception $e) {
            return null;
        }
    }
}

if (!function_exists('next_sched')) {
    function next_sched(PDO $pdo, string $m): string {
        if ((string)sched_val($pdo, "sched_enabled_$m", '0') !== '1') {
            return 'выключено';
        }
        $tz  = new DateTimeZone('Europe/Moscow');
        $now = new DateTime('now', $tz);

        $period = max(1, (int)sched_val($pdo, "sched_period_$m", '2'));
        $at     = sched_val($pdo, "sched_time_$m", '10:00');
        $h = 10; $mi = 0;
        if (preg_match('/^(\d{1,2}):(\d{2})$/', $at, $mm)) { $h = (int)$mm[1]; $mi = (int)$mm[2]; }
        $todayAt = (clone $now)->setTime($h, $mi, 0);

        // дата старта: если она в будущем — расписание раньше не сработает
        $startRaw = trim(sched_val($pdo, "sched_start_$m", ''));
        $startDt = preg_match('/^\d{4}-\d{2}-\d{2}$/', $startRaw) ? sched_parse($startRaw . ' 00:00:00', $tz) : null;
        if ($startDt && $now->format('Y-m-d') < $startDt->format('Y-m-d')) {
            return $startDt->format('d.m.Y') . ' ' . $at . ' (старт)';
        }

        // когда модуль запускался: сначала отметка расписания, потом любой прогон
        $label = ['friends_check' => 'Friends_check', 'comments' => 'Comments',
                  'messages' => 'Messages', 'cleanup' => 'Friend_requests_delete'][$m] ?? $m;
        $q = $pdo->prepare('SELECT value FROM state WHERE key = ?');
        $q->execute(["sched_last_$m"]);
        $schedLast = (string)($q->fetchColumn() ?: '');
        $q->execute(["last_run_$label"]);
        $anyLast = (string)($q->fetchColumn() ?: '');
        $r = $pdo->prepare('SELECT started_at FROM module_runs WHERE module = ? ORDER BY id DESC LIMIT 1');
        $r->execute([$m]);
        $runLast = (string)($r->fetchColumn() ?: '');
        $last = $schedLast !== '' ? $schedLast : ($runLast !== '' ? $runLast : $anyLast);

        $anchor = null;
        if ($last !== '') {
            $anchor = sched_parse($last, $tz);      // надёжный разбор: и «... 06:00:00», и «... 06:00»
        }
        // якорь — более поздняя из дат: последний запуск и дата старта
        if ($startDt && (!$anchor || $anchor < $startDt)) { $anchor = $startDt; }

        if (!$anchor) {
            return $now->format('d.m.Y') . ' ' . $at . ($now < $todayAt ? '' : ' (пора)');
        }

        $anchorDate = (clone $anchor)->setTime(0, 0, 0);
        $days = (int)$anchorDate->diff((clone $now)->setTime(0, 0, 0))->days;

        // сегодня уже отработал по расписанию — следующий не раньше чем через период
        if ($schedLast !== '' && substr($schedLast, 0, 10) === $now->format('Y-m-d')) {
            $days = 0;
        }
        // день по графику наступил
        if ($days >= $period) {
            return $now < $todayAt ? $now->format('d.m.Y') . ' ' . $at : 'сейчас (пора)';
        }

        $next = (clone $anchorDate)->modify('+' . $period . ' days')->setTime($h, $mi, 0);
        $guard = 0;
        while ($next <= $now && $guard++ < 400) {
            $next = (clone $next)->modify('+' . $period . ' days');
        }
        $delta = (int)(clone $now)->setTime(0, 0, 0)->diff((clone $next)->setTime(0, 0, 0))->days;
        return $next->format('d.m.Y H:i');
    }
}
