package cz.moneta.test.harness.connectors.database;

import org.jooq.Configuration;
import org.jooq.DSLContext;
import org.jooq.Record;
import org.jooq.Result;
import org.jooq.Routine;
import org.jooq.SQLDialect;
import org.jooq.TableRecord;
import org.jooq.impl.DSL;
import org.jooq.impl.DefaultConfiguration;
import org.jooq.impl.DefaultConnectionProvider;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.function.Consumer;
import java.util.function.Function;

public class OracleConnector extends DatabaseConnector {

    public OracleConnector(String url, String user, String password) {
        super(url, user, password);
    }

    public <R extends TableRecord<R>> R executeDsl(Function<DSLContext, R> query) {
        try (Connection connection = DriverManager.getConnection(getUrl(), getUser(), getPassword())) {
            return query.apply(DSL.using(connection, SQLDialect.ORACLE));
        } catch (SQLException e) {
            throw new RuntimeException("Error querying database", e);
        }
    }

    public <K> K insertDsl(Function<DSLContext, K> query) {
        try (Connection connection = DriverManager.getConnection(getUrl(), getUser(), getPassword())) {
            return query.apply(DSL.using(connection, SQLDialect.ORACLE));
        } catch (SQLException e) {
            throw new RuntimeException("Error querying database", e);
        }
    }

    public <R extends Routine<?>> R executeProcedure(R procedure) {
        try (Connection connection = DriverManager.getConnection(getUrl(), getUser(), getPassword())) {
            Configuration configuration = new DefaultConfiguration()
                    .derive(new DefaultConnectionProvider(connection))
                    .derive(SQLDialect.ORACLE);
            procedure.execute(configuration);
            return procedure;
        } catch (SQLException e) {
            throw new RuntimeException("Error executing procedure database", e);
        }
    }

    public Result<Record> executeSql(String sql) {
        return super.executeSql(sql, SQLDialect.ORACLE);
    }

    public void executeStatement(Consumer<Connection> execute) {
        try (Connection connection = DriverManager.getConnection(getUrl(), getUser(), getPassword())) {
            execute.accept(connection);
        } catch (SQLException e) {
            throw new RuntimeException("Error executing statement", e);
        }
    }
}
