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

/**
 * Outbound port for exclusive run locking.
 * <p>
 * This port abstracts the mechanism for ensuring that only one instance of the PDF Umbenenner
 * is executing at any given time. The port defines the contract without prescribing the
 * implementation (e.g., file-based locks, OS-level locks, distributed locks).
 * <p>
 * Responsibilities:
 * <ul>
 *   <li>Guarantee exclusive access to shared resources (SQLite database, target directory)</li>
 *   <li>Prevent concurrent batch runs from overwriting each other's work or causing inconsistencies</li>
 *   <li>Allow controlled startup failure if another instance is already running</li>
 * </ul>
 * <p>
 * Lock Lifecycle:
 * <ul>
 *   <li>Acquire the lock at batch startup (before any processing)</li>
 *   <li>Hold the lock for the entire batch run</li>
 *   <li>Release the lock cleanly at batch end (even on failure, if possible)</li>
 * </ul>
 *
 */
public interface RunLockPort {

    /**
     * Acquires an exclusive lock for the batch run.
     * <p>
     * This method blocks or throws an exception if the lock cannot be acquired
     * (e.g., another instance already holds it). The behavior depends on the implementation.
     * <p>
     * If this method returns normally, the caller holds the lock and must ensure
     * {@link #release()} is called to free it, typically in a finally block.
     *
     * @throws RunLockUnavailableException if the lock cannot be acquired
     *         (e.g., another instance already holds it or system error prevents acquiring)
     * @throws RuntimeException for other critical lock-related failures
     */
    void acquire();

    /**
     * Releases the exclusive lock held by this batch run.
     * <p>
     * This method is called after batch processing completes (successfully or not)
     * to allow other instances to run.
     * <p>
     * Implementations should handle the case where release is called multiple times
     * or when no lock is currently held, avoiding exceptions if possible.
     *
     * @throws RuntimeException if lock release fails critically
     */
    void release();
}
