package example;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.postgresql.ds.PGSimpleDataSource;

public final class Database {
    private Database() {}
    public static Connection open() throws SQLException { return open(false); }
    public static Connection open(boolean rewriteBatch) throws SQLException {
        PGSimpleDataSource dataSource = new PGSimpleDataSource();
        dataSource.setURL(required("LAB_DB_URL"));
        dataSource.setUser("lab_app");
        dataSource.setPassword(required("LAB_APP_PASSWORD"));
        dataSource.setConnectTimeout(3);
        dataSource.setSocketTimeout(5);
        dataSource.setApplicationName("transaction-lab");
        dataSource.setReWriteBatchedInserts(rewriteBatch);
        return dataSource.getConnection();
    }
    private static String required(String name) {
        String value = System.getenv(name);
        if (value == null || value.isBlank()) throw new IllegalArgumentException("Missing " + name);
        return value;
    }
    public static long scalar(String sql) throws SQLException {
        try (Connection connection = open()) { return scalar(connection, sql); }
    }
    public static long scalar(Connection connection, String sql) throws SQLException {
        try (PreparedStatement statement = connection.prepareStatement(sql); ResultSet rows = statement.executeQuery()) {
            require(rows.next(), "No query row");
            return rows.getLong(1);
        }
    }
    public static void execute(Connection connection, String sql) throws SQLException {
        try (PreparedStatement statement = connection.prepareStatement(sql)) { statement.execute(); }
    }
    public static void reset() throws SQLException {
        try (Connection connection = open()) {
            execute(connection, "delete from ledger");
            execute(connection, "delete from import_item");
            execute(connection, "update account set balance_cents = 1000 where id = 1");
        }
    }
    public static void rollback(Connection connection, Throwable original) {
        try { connection.rollback(); } catch (SQLException cleanup) { original.addSuppressed(cleanup); }
    }
    public static void require(boolean condition, String message) {
        if (!condition) throw new AssertionError(message);
    }
}
