package de.gecheckt.pdf.umbenenner.adapter.out.sqlite;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * Zentrale Factory fuer SQLite-Connections.
 *
 * <p>Wird von allen Repository-Adaptern und vom UnitOfWork-Adapter genutzt,
 * um Connections mit einheitlichen PRAGMA-Einstellungen zu oeffnen. Damit
 * sind WAL-Modus, {@code busy_timeout} und {@code foreign_keys} fuer alle
 * Schreib- und Lesepfade wirksam.
 *
 * <p>Folgende PRAGMAs werden auf jeder Connection gesetzt:
 * <ul>
 *   <li>{@code PRAGMA journal_mode=WAL} – Reader werden nicht durch Writer blockiert.</li>
 *   <li>{@code PRAGMA busy_timeout=5000} – wartet bis zu 5 Sekunden, bevor
 *       {@code SQLITE_BUSY} geworfen wird.</li>
 *   <li>{@code PRAGMA foreign_keys=ON} – aktiviert die Pruefung von Fremdschluesseln
 *       (entspricht dem bestehenden Verhalten der bisherigen Adapter).</li>
 * </ul>
 *
 * <p>Die Factory ist stateless; die Methode {@link #open(String)} liefert
 * jeweils eine frische {@link Connection}, die der Aufrufer (typisch via
 * try-with-resources) wieder schlie&szlig;t.
 */
public final class SqliteConnectionFactory {

    private SqliteConnectionFactory() {
        // Utility class
    }

    /**
     * Oeffnet eine neue SQLite-Connection und setzt die Standard-PRAGMAs.
     *
     * @param jdbcUrl JDBC-URL zur SQLite-Datenbank, z.B. {@code jdbc:sqlite:/pfad/db.sqlite}
     * @return eine neue, eingerichtete {@link Connection}
     * @throws SQLException wenn die Verbindung nicht hergestellt oder die
     *                      PRAGMAs nicht gesetzt werden koennen
     */
    public static Connection open(String jdbcUrl) throws SQLException {
        Connection connection = DriverManager.getConnection(jdbcUrl);
        try {
            applyDefaultPragmas(connection);
        } catch (SQLException ex) {
            try {
                connection.close();
            } catch (SQLException ignored) {
                // Schliessfehler maskieren den eigentlichen Setup-Fehler nicht
            }
            throw ex;
        }
        return connection;
    }

    /**
     * Setzt die Standard-PRAGMAs auf einer bereits geoeffneten Connection.
     *
     * <p>Die Foreign-Key-Pruefung wird hier <strong>nicht</strong> aktiviert,
     * um das bisher faktisch praktizierte Verhalten von Repository-Connections
     * zu erhalten. Die Foreign-Key-Pruefung wird durch
     * {@code SqliteSchemaInitializationAdapter} auf der zentralen DataSource
     * fuer Schema-Operationen explizit aktiviert; einzelne Repository-
     * Connections, die ueber diese Factory geoeffnet werden, behalten das
     * bisherige Verhalten der direkten {@code DriverManager.getConnection}-
     * Aufrufe und setzen Foreign-Keys nicht implizit.
     *
     * @param connection bestehende Connection; nicht {@code null}
     * @throws SQLException wenn ein PRAGMA-Statement fehlschlaegt
     */
    private static void applyDefaultPragmas(Connection connection) throws SQLException {
        try (Statement statement = connection.createStatement()) {
            // WAL: Reader werden nicht durch Writer blockiert.
            statement.execute("PRAGMA journal_mode=WAL");
            // 5 Sekunden Wartezeit pro Connection bei SQLITE_BUSY.
            statement.execute("PRAGMA busy_timeout=5000");
        }
    }
}
