package de.gecheckt.pdf.umbenenner.application.validation.editor;

import java.util.Objects;
import java.util.Optional;

/**
 * Ein einzelner Validierungsbefund für den aktuellen Editorzustand.
 * <p>
 * Ein Befund beschreibt eine erkannte Auffälligkeit in der Konfiguration mit einem
 * Schweregrad, einem Feldbezug und einer deutschen Beschreibung. Das {@code fieldKey}-Feld
 * verwendet denselben Property-Schlüssel wie die {@code .properties}-Datei
 * (z. B. {@code "source.folder"} oder {@code "ai.provider.openai-compatible.apiKey"}).
 * <p>
 * Ein Befund kann entweder feld-spezifisch sein (mit gesetztem {@code fieldKey}) oder
 * allgemein (mit leerem {@code fieldKey}), wenn er sich nicht auf ein einzelnes Feld bezieht.
 * <p>
 * Befunde sind immutable und enthalten keine JavaFX-Typen.
 *
 * @param fieldKey  optionaler Property-Schlüssel des betroffenen Felds; leer wenn feld-unabhängig
 * @param severity  Schweregrad des Befunds; nie {@code null}
 * @param message   deutschsprachige Beschreibung; nie {@code null}
 */
public record EditorValidationFinding(
        Optional<String> fieldKey,
        EditorValidationSeverity severity,
        String message) {
    private static final String FIELD_KEY_NOT_NULL = "fieldKey must not be null";


    /**
     * Erstellt einen neuen Validierungsbefund.
     *
     * @param fieldKey  optionaler Property-Schlüssel; {@code null} wird zu {@link Optional#empty()}
     * @param severity  Schweregrad; darf nicht {@code null} sein
     * @param message   deutschsprachige Beschreibung; darf nicht {@code null} sein
     * @throws NullPointerException wenn {@code severity} oder {@code message} {@code null} sind
     */
    public EditorValidationFinding {
        Objects.requireNonNull(severity, "severity must not be null");
        Objects.requireNonNull(message, "message must not be null");
        fieldKey = Objects.requireNonNullElse(fieldKey, Optional.empty());
    }

    /**
     * Erstellt einen feldbezogenen Fehler-Befund.
     *
     * @param fieldKey  Property-Schlüssel des betroffenen Felds; darf nicht {@code null} sein
     * @param message   deutschsprachige Fehlerbeschreibung; darf nicht {@code null} sein
     * @return ein neuer Befund mit Schweregrad {@link EditorValidationSeverity#ERROR}
     */
    public static EditorValidationFinding error(String fieldKey, String message) {
        Objects.requireNonNull(fieldKey, FIELD_KEY_NOT_NULL);
        return new EditorValidationFinding(Optional.of(fieldKey), EditorValidationSeverity.ERROR, message);
    }

    /**
     * Erstellt einen feldbezogenen Warn-Befund.
     *
     * @param fieldKey  Property-Schlüssel des betroffenen Felds; darf nicht {@code null} sein
     * @param message   deutschsprachige Warnbeschreibung; darf nicht {@code null} sein
     * @return ein neuer Befund mit Schweregrad {@link EditorValidationSeverity#WARNING}
     */
    public static EditorValidationFinding warning(String fieldKey, String message) {
        Objects.requireNonNull(fieldKey, FIELD_KEY_NOT_NULL);
        return new EditorValidationFinding(Optional.of(fieldKey), EditorValidationSeverity.WARNING, message);
    }

    /**
     * Erstellt einen feldbezogenen Hinweis-Befund.
     *
     * @param fieldKey  Property-Schlüssel des betroffenen Felds; darf nicht {@code null} sein
     * @param message   deutschsprachige Hinweisbeschreibung; darf nicht {@code null} sein
     * @return ein neuer Befund mit Schweregrad {@link EditorValidationSeverity#HINT}
     */
    public static EditorValidationFinding hint(String fieldKey, String message) {
        Objects.requireNonNull(fieldKey, FIELD_KEY_NOT_NULL);
        return new EditorValidationFinding(Optional.of(fieldKey), EditorValidationSeverity.HINT, message);
    }

    /**
     * Erstellt einen allgemeinen Informationsbefund ohne Feldbezug.
     *
     * @param message  deutschsprachige Informationsbeschreibung; darf nicht {@code null} sein
     * @return ein neuer Befund mit Schweregrad {@link EditorValidationSeverity#INFO}
     */
    public static EditorValidationFinding info(String message) {
        return new EditorValidationFinding(Optional.empty(), EditorValidationSeverity.INFO, message);
    }

    /**
     * Erstellt einen feldbezogenen Informationsbefund.
     *
     * @param fieldKey  Property-Schlüssel des betroffenen Felds; darf nicht {@code null} sein
     * @param message   deutschsprachige Informationsbeschreibung; darf nicht {@code null} sein
     * @return ein neuer Befund mit Schweregrad {@link EditorValidationSeverity#INFO}
     */
    public static EditorValidationFinding info(String fieldKey, String message) {
        Objects.requireNonNull(fieldKey, FIELD_KEY_NOT_NULL);
        return new EditorValidationFinding(Optional.of(fieldKey), EditorValidationSeverity.INFO, message);
    }

    /**
     * Gibt an, ob dieser Befund feld-spezifisch ist.
     *
     * @return {@code true} wenn ein {@code fieldKey} gesetzt ist
     */
    public boolean hasFieldKey() {
        return fieldKey.isPresent();
    }
}
