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

import java.util.function.Consumer;

import de.gecheckt.pdf.umbenenner.domain.model.DocumentFingerprint;

/**
 * Port for executing multiple repository operations within a single unit of work.
 * <p>
 * Ensures that related persistence operations (such as saving a processing attempt
 * and updating a document record) are executed atomically.
 */
public interface UnitOfWorkPort {

    /**
     * Executes the given operations within a single unit of work.
     * <p>
     * If any operation fails, all changes are rolled back and the exception is propagated.
     *
     * @param operations the operations to execute; must not be null
     * @throws DocumentPersistenceException if any operation fails
     */
    void executeInTransaction(Consumer<TransactionOperations> operations);

    /**
     * Operations available within a transaction.
     */
    interface TransactionOperations {

        /**
         * Saves a processing attempt within the current transaction.
         *
         * @param attempt the attempt to persist; must not be null
         */
        void saveProcessingAttempt(ProcessingAttempt attempt);

        /**
         * Creates a new document master record within the current transaction.
         *
         * @param record the new record to persist; must not be null
         */
        void createDocumentRecord(DocumentRecord record);

        /**
         * Updates an existing document master record within the current transaction.
         *
         * @param record the updated record; must not be null; fingerprint must exist
         */
        void updateDocumentRecord(DocumentRecord record);

        /**
         * Deletes all attempt history entries and the document master record for the
         * given fingerprint within the current transaction.
         * <p>
         * Deletion order must respect foreign-key constraints: attempt history rows are
         * removed first, then the master record. This operation is idempotent — if no
         * data exists for the fingerprint the method returns silently.
         *
         * @param fingerprint the document identity to fully reset; must not be null
         * @throws DocumentPersistenceException if the delete fails due to a technical error
         */
        void resetDocumentByFingerprint(DocumentFingerprint fingerprint);

        /**
         * Setzt ausschließlich die vier fachlich relevanten Status-Felder zurück,
         * ohne die Versuchshistorie zu löschen.
         * <p>
         * Folgende Felder werden aktualisiert:
         * <ul>
         *   <li>{@code overall_status} → {@code READY_FOR_AI}</li>
         *   <li>{@code content_error_count} → {@code 0}</li>
         *   <li>{@code transient_error_count} → {@code 0}</li>
         *   <li>{@code last_failure_instant} → {@code null}</li>
         * </ul>
         * Nicht geändert werden: {@code created_at}, {@code last_success_instant},
         * {@code last_target_path}, {@code last_target_file_name} sowie alle
         * {@code processing_attempt}-Einträge, die vollständig erhalten bleiben.
         * <p>
         * Nach diesem Aufruf gilt das Dokument beim nächsten Lauf als verarbeitbar.
         *
         * @param fingerprint der Dokumentbezeichner, dessen Status zurückgesetzt werden soll;
         *                    darf nicht {@code null} sein
         * @throws DocumentPersistenceException bei technischen Datenbankfehlern
         */
        void resetDocumentStatusForRetry(DocumentFingerprint fingerprint);
    }
}