package de.gecheckt.pdf.umbenenner.adapter.in.gui.editor;

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

/**
 * Represents a single entry in the central message area of the GUI configuration editor.
 * <p>
 * Each entry carries a severity level, the message text, an optional source label that
 * identifies the subsystem that produced the message (e.g., "Modellabruf", "Validierung"),
 * and a timestamp. The GUI renders the {@link GuiMessageSeverity#getPrefixLabel() prefix} of
 * the severity in colour while the message text itself remains black.
 * <p>
 * Instances are immutable and contain no JavaFX references; they are safe to create on
 * background threads and pass to the JavaFX Application Thread via {@code Platform.runLater}.
 *
 * @param severity  the severity of this message; never {@code null}
 * @param text      the message text; never {@code null}
 * @param source    optional label identifying the origin subsystem; empty when not applicable
 * @param timestamp the instant at which the message was created; never {@code null}
 */
public record GuiMessageEntry(
        GuiMessageSeverity severity,
        String text,
        Optional<String> source,
        Instant timestamp) {

    /**
     * Creates a new message entry.
     *
     * @param severity  severity level; must not be {@code null}
     * @param text      message text; must not be {@code null}
     * @param source    optional source label; {@code null} is treated as {@link Optional#empty()}
     * @param timestamp creation timestamp; must not be {@code null}
     * @throws NullPointerException if {@code severity}, {@code text}, or {@code timestamp} is {@code null}
     */
    public GuiMessageEntry {
        Objects.requireNonNull(severity, "severity must not be null");
        Objects.requireNonNull(text, "text must not be null");
        Objects.requireNonNull(timestamp, "timestamp must not be null");
        source = Objects.requireNonNullElse(source, Optional.empty());
    }

    /**
     * Creates a message entry without a source label, using the current instant as timestamp.
     *
     * @param severity severity level; must not be {@code null}
     * @param text     message text; must not be {@code null}
     * @return a new entry; never {@code null}
     */
    public static GuiMessageEntry of(GuiMessageSeverity severity, String text) {
        return new GuiMessageEntry(severity, text, Optional.empty(), Instant.now());
    }

    /**
     * Creates a message entry with a source label, using the current instant as timestamp.
     *
     * @param severity severity level; must not be {@code null}
     * @param text     message text; must not be {@code null}
     * @param source   source subsystem label; must not be {@code null}
     * @return a new entry; never {@code null}
     */
    public static GuiMessageEntry of(GuiMessageSeverity severity, String text, String source) {
        Objects.requireNonNull(source, "source must not be null");
        return new GuiMessageEntry(severity, text, Optional.of(source), Instant.now());
    }
}
