package de.gecheckt.pdf.umbenenner.application.usecase;

import java.util.List;
import java.util.Objects;

import de.gecheckt.pdf.umbenenner.application.port.out.history.DocumentHistoryRow;
import de.gecheckt.pdf.umbenenner.application.port.out.history.HistoryQuery;
import de.gecheckt.pdf.umbenenner.application.port.out.history.HistoryQueryPort;

/**
 * Use-Case-Implementierung für das Laden der Dokumentenliste im Historien-Tab.
 * <p>
 * Delegiert die Datenbankabfrage vollständig an {@link HistoryQueryPort} und
 * wertet das LIMIT-501-Ergebnis aus, um der GUI signalisieren zu können, ob
 * weitere Einträge vorhanden sind, die durch einen engeren Filter erreichbar wären.
 * <p>
 * <strong>LIMIT-501-Technik:</strong> Die Query wird mit {@code limit + 1 = 501}
 * ausgeführt (sofern das übergebene Limit 500 beträgt). Wenn die Datenbank 501
 * Zeilen zurückgibt, existieren mehr als 500 Treffer. Die zurückgegebene Liste
 * enthält dann exakt 500 Zeilen (das letzte Element wird verworfen) und
 * {@link HistoryOverviewResult#hasMore()} liefert {@code true}.
 */
public class DefaultHistoryOverviewUseCase {

    private static final int MAX_DISPLAY_COUNT = 500;

    private final HistoryQueryPort historyQueryPort;

    /**
     * Erzeugt den Use-Case mit dem erforderlichen Abfrage-Port.
     *
     * @param historyQueryPort Port für lesende Historienabfragen; darf nicht {@code null} sein
     * @throws NullPointerException wenn {@code historyQueryPort} null ist
     */
    public DefaultHistoryOverviewUseCase(HistoryQueryPort historyQueryPort) {
        this.historyQueryPort = Objects.requireNonNull(historyQueryPort, "historyQueryPort darf nicht null sein");
    }

    /**
     * Lädt die Dokumentenliste auf Basis der übergebenen Abfrageparameter.
     * <p>
     * Intern wird ein Limit von 501 verwendet, um erkennen zu können, ob mehr
     * als 500 Treffer vorhanden sind.
     *
     * @param query Abfrageparameter mit Suchtext, Status-Filter und Limit; darf nicht {@code null} sein
     * @return Ergebnisobjekt mit Trefferlist und {@code hasMore}-Flag; nie {@code null}
     * @throws de.gecheckt.pdf.umbenenner.application.port.out.DocumentPersistenceException
     *         bei technischen Datenbankfehlern
     */
    public HistoryOverviewResult loadOverview(HistoryQuery query) {
        Objects.requireNonNull(query, "query darf nicht null sein");

        List<DocumentHistoryRow> rows = historyQueryPort.loadOverview(query);

        if (rows.size() > MAX_DISPLAY_COUNT) {
            // 501 Zeilen zurückgegeben: mehr als 500 Treffer vorhanden
            List<DocumentHistoryRow> truncated = List.copyOf(rows.subList(0, MAX_DISPLAY_COUNT));
            return new HistoryOverviewResult(truncated, true);
        }

        return new HistoryOverviewResult(List.copyOf(rows), false);
    }

    /**
     * Ergebnis einer Historien-Übersichtsabfrage.
     *
     * @param rows    Liste der Trefferzeilen; nie {@code null}; enthält maximal 500 Einträge
     * @param hasMore {@code true}, wenn mehr als 500 Treffer vorhanden sind und durch
     *                einen engeren Filter eingegrenzt werden könnten
     */
    public record HistoryOverviewResult(List<DocumentHistoryRow> rows, boolean hasMore) {

        /**
         * Kompakter Konstruktor mit Pflichtfeldprüfung.
         *
         * @throws NullPointerException wenn {@code rows} null ist
         */
        public HistoryOverviewResult {
            Objects.requireNonNull(rows, "rows darf nicht null sein");
        }
    }
}
