package de.gecheckt.pdf.umbenenner.application.port.in;

import java.time.Instant;
import java.util.Objects;
import java.util.Optional;

import de.gecheckt.pdf.umbenenner.application.port.out.RunSummary;

/**
 * Unveränderlicher Snapshot des aktuellen Scheduler-Zustands.
 * <p>
 * Instanzen dieses Records sind threadsicher, da alle Felder final sind.
 * Im {@code DefaultSchedulerControlUseCase} werden Snapshots atomar über
 * eine {@code AtomicReference<SchedulerStatus>} ausgetauscht.
 * <p>
 * Die GUI liest diesen Snapshot regelmäßig über eine zentrale
 * Status-Refresh-Timeline (1 Hz) und aktualisiert Scheduler-Tab,
 * Batch-Tab und Konfig-Tab entsprechend.
 *
 * @param state           aktueller Lebenszykluszustand des Schedulers
 * @param lastRunEndedAt  Endzeitpunkt des letzten abgeschlossenen Laufs;
 *                        leer vor dem ersten Lauf
 * @param lastRunSummary  Zusammenfassung des letzten abgeschlossenen Laufs;
 *                        leer vor dem ersten Lauf
 * @param nextTickAt      geplanter Zeitpunkt des nächsten Ticks;
 *                        nur befüllt wenn {@code state == RUNNING_IDLE}
 * @param lastError       letzte aufgetretene deutsche Fehlermeldung;
 *                        wird bei erfolgreichem Lauf gelöscht,
 *                        bei {@code SkippedBusy} unverändert gelassen
 * @param sessionTotals   aggregierte Zähler seit dem letzten Sitzungsstart;
 *                        leer vor dem allerersten {@code start()}, ab dem
 *                        ersten erfolgreichen Start gefüllt und bei jedem
 *                        weiteren Start auf null zurückgesetzt; nach dem
 *                        Stopp bleibt der eingefrorene Endwert sichtbar
 */
public record SchedulerStatus(
        SchedulerState state,
        Optional<Instant> lastRunEndedAt,
        Optional<RunSummary> lastRunSummary,
        Optional<Instant> nextTickAt,
        Optional<String> lastError,
        Optional<SchedulerSessionTotals> sessionTotals
) {

    /**
     * Validiert, dass Pflichtfelder und Optional-Felder nicht null sind.
     */
    public SchedulerStatus {
        if (state == null) {
            throw new IllegalArgumentException("state darf nicht null sein");
        }
        Objects.requireNonNull(lastRunEndedAt, "lastRunEndedAt darf nicht null sein");
        Objects.requireNonNull(lastRunSummary, "lastRunSummary darf nicht null sein");
        Objects.requireNonNull(nextTickAt, "nextTickAt darf nicht null sein");
        Objects.requireNonNull(lastError, "lastError darf nicht null sein");
    }

    /**
     * Erzeugt den initialen Scheduler-Status beim Programmstart.
     * <p>
     * Zustand ist {@link SchedulerState#STOPPED} und alle optionalen Felder
     * sind leer.
     *
     * @return initialer Scheduler-Status
     */
    public static SchedulerStatus initial() {
        return new SchedulerStatus(
                SchedulerState.STOPPED,
                Optional.empty(),
                Optional.empty(),
                Optional.empty(),
                Optional.empty(),
                Optional.empty()
        );
    }
}
