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

import java.nio.file.Path;
import java.util.Objects;

/**
 * Inbound-Port zum Anlegen einer neuen, leeren SQLite-Datenbankdatei und zum Umstellen
 * der aktiven Datenbankreferenz der Anwendung auf diese neue Datei.
 * <p>
 * Der Use-Case orchestriert den vollständigen, aus Anwendungssicht atomaren Ablauf:
 * <ol>
 *   <li>Pfad-Sicherheitsprüfung: aktive DB darf nicht überschrieben werden;</li>
 *   <li>Erzeugung einer temporären SQLite-Datei im Zielverzeichnis;</li>
 *   <li>vollständige Schema-Migration auf den neuesten Stand;</li>
 *   <li>Verbindungstest gegen die migrierte Temp-Datei;</li>
 *   <li>atomarer Move auf den endgültigen Zielpfad
 *       ({@link java.nio.file.StandardCopyOption#ATOMIC_MOVE},
 *       {@link java.nio.file.StandardCopyOption#REPLACE_EXISTING});</li>
 *   <li>Umstellung der aktiven DB-Referenz über den
 *       {@link de.gecheckt.pdf.umbenenner.application.port.out.ActiveDatabaseContextPort}.</li>
 * </ol>
 * <p>
 * Schlägt ein Schritt fehl, bleibt die bisher aktive DB unverändert in Betrieb. Die
 * temporäre Datei wird im Fehlerfall zuverlässig entfernt.
 */
@FunctionalInterface
public interface CreateNewDatabaseUseCase {

    /**
     * Legt eine neue, leere SQLite-Datenbankdatei am übergebenen Zielpfad an und stellt
     * die aktive Datenbankreferenz der Anwendung auf diese Datei um.
     *
     * @param targetFile der vom Benutzer ausgewählte Zielpfad; darf nicht {@code null}
     *                   sein. Bei einer bereits existierenden Datei muss der Aufrufer
     *                   vorab die Bestätigung des Benutzers eingeholt haben.
     * @return strukturiertes Ergebnis mit Erfolg oder klassifiziertem Fehler; nie
     *         {@code null}
     * @throws NullPointerException wenn {@code targetFile} {@code null} ist
     */
    CreateNewDatabaseResult createNewDatabase(Path targetFile);

    /**
     * Versiegeltes Ergebnis-Interface für {@link CreateNewDatabaseUseCase#createNewDatabase(Path)}.
     */
    sealed interface CreateNewDatabaseResult
            permits CreateNewDatabaseResult.Success,
                    CreateNewDatabaseResult.SameAsActiveDatabase,
                    CreateNewDatabaseResult.CreationFailed {

        /**
         * Erfolgsfall. Die neue Datenbank wurde angelegt, migriert, getestet und ist
         * jetzt die aktive Datenbank der Anwendung.
         *
         * @param targetFile absoluter Pfad der neuen aktiven Datenbankdatei; nie
         *                   {@code null}
         */
        record Success(Path targetFile) implements CreateNewDatabaseResult {

            /**
             * Konstruktor mit Pflichtprüfung.
             *
             * @param targetFile absoluter Pfad der neuen aktiven Datenbankdatei; darf
             *                   nicht {@code null} sein
             * @throws NullPointerException wenn {@code targetFile} {@code null} ist
             */
            public Success {
                Objects.requireNonNull(targetFile, "targetFile darf nicht null sein");
            }
        }

        /**
         * Fehlerfall: Der gewählte Zielpfad ist die aktuell aktive Datenbankdatei.
         * Diese darf nicht überschrieben werden. Die aktive DB bleibt unverändert.
         *
         * @param targetFile der vom Benutzer gewählte Zielpfad; nie {@code null}
         */
        record SameAsActiveDatabase(Path targetFile) implements CreateNewDatabaseResult {

            /**
             * Konstruktor mit Pflichtprüfung.
             *
             * @param targetFile der vom Benutzer gewählte Zielpfad; darf nicht
             *                   {@code null} sein
             * @throws NullPointerException wenn {@code targetFile} {@code null} ist
             */
            public SameAsActiveDatabase {
                Objects.requireNonNull(targetFile, "targetFile darf nicht null sein");
            }
        }

        /**
         * Fehlerfall: Beim Anlegen, Migrieren, Testen oder beim atomaren Move ist ein
         * technischer Fehler aufgetreten. Die aktive DB bleibt unverändert; eine evtl.
         * angelegte Temp-Datei wurde entfernt.
         *
         * @param phase   technische Phase, in der der Fehler auftrat; nie {@code null}
         * @param message kurze, deutsche Fehlerbeschreibung; nie {@code null}
         * @param cause   ursächliche Ausnahme; kann {@code null} sein
         */
        record CreationFailed(Phase phase, String message, Throwable cause)
                implements CreateNewDatabaseResult {

            /**
             * Konstruktor mit Pflichtprüfung der nicht-nullbaren Felder.
             *
             * @param phase   technische Phase; darf nicht {@code null} sein
             * @param message kurze, deutsche Fehlerbeschreibung; darf nicht
             *                {@code null} sein
             * @param cause   ursächliche Ausnahme; kann {@code null} sein
             * @throws NullPointerException wenn {@code phase} oder {@code message}
             *                              {@code null} ist
             */
            public CreationFailed {
                Objects.requireNonNull(phase, "phase darf nicht null sein");
                Objects.requireNonNull(message, "message darf nicht null sein");
            }
        }

        /**
         * Technische Phase, in der ein Fehler aufgetreten ist.
         */
        enum Phase {
            /** Pfad-Sicherheitsprüfung (z. B. Auflösung über {@code toRealPath()}) ist fehlgeschlagen. */
            PATH_RESOLUTION,
            /** Anlage der temporären Datei ist fehlgeschlagen. */
            FILE_CREATION,
            /** Schema-Migration der temporären Datei ist fehlgeschlagen. */
            SCHEMA_MIGRATION,
            /** Verbindungstest gegen die migrierte Datei ist fehlgeschlagen. */
            CONNECTION_TEST,
            /**
             * Atomarer Move der temporären Datei zum Zielpfad ist fehlgeschlagen –
             * insbesondere wenn das Dateisystem die Kombination
             * {@code ATOMIC_MOVE + REPLACE_EXISTING} nicht unterstützt. Es wird
             * absichtlich kein nicht-atomarer Fallback durchgeführt.
             */
            ATOMIC_MOVE,
            /** Umstellung der aktiven DB-Referenz ist fehlgeschlagen. */
            CONTEXT_SWITCH
        }
    }
}
