/*
 * Copyright © 2012-2025 by Data Virtuality GmbH
 */
package org.teiid.translator.jdbc;

import org.junit.jupiter.api.Test;
import org.teiid.metadata.MetadataFactory;
import org.teiid.translator.jdbc.postgresql.PostgreSQLExecutionFactory;

import java.sql.*;
import java.util.Properties;

import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.*;

/**
 *
 *
 * @author Roman Pedchenko
 * @date 2025.09.16
 */
public class TestMetadataProcessorInterruption {
    public static final String TESTEXC = "testexc1";

    @Test
    public void testSkipTableByTable() throws Exception {
        var ef = new PostgreSQLExecutionFactory();
        baseSkipTableByTableTest((mf, c, md) -> {
            when(md.getColumns(any(), any(), any(), any())).thenThrow(new SQLException(TESTEXC));
            ef.getMetadata(mf, c);
            verify(md, times(2)).getTables(any(), any(), any(), any());
            verify(md, times(2)).getColumns(any(), any(), any(), any());
        });
    }

    @Test
    public void testSkipTableByTableInterrupted() throws Exception {
        var ef = new PostgreSQLExecutionFactory();
        baseSkipTableByTableTest((mf, c, md) -> {
            when(md.getColumns(any(), any(), any(), any())).thenThrow(new SQLException(TESTEXC, "INTERRUPTED"));
            assertThatThrownBy(() -> ef.getMetadata(mf, c)).cause().isInstanceOf(SQLException.class).hasMessage(TESTEXC);
            verify(md, times(1)).getTables(any(), any(), any(), any());
            verify(md, times(1)).getColumns(any(), any(), any(), any());
        });
    }

    public static void baseSkipTableByTableTest(Checker test) throws Exception {
        var mf = new MetadataFactory("vdb1", 1, "schema1", null, new Properties(), null);
        try (var c = mock(Connection.class)) {
            final DatabaseMetaData md = mock(DatabaseMetaData.class);
            final ResultSet rs = getTableRs();
            final ResultSet rs1 = getTableRs();
            when(md.getTables(any(), any(), any(), any())).thenReturn(rs, rs1);
            when(c.getMetaData()).thenReturn(md);
            test.check(mf, c, md);
        }
    }

    private static ResultSet getTableRs() throws Exception {
        var rs = mock(ResultSet.class);
        ResultSetMetaData rsmd = mock(ResultSetMetaData.class);
        when(rsmd.getColumnCount()).thenReturn(3);
        when(rs.getMetaData()).thenReturn(rsmd);
        when(rs.next()).thenReturn(true, false);
        when(rs.getString(eq(2))).thenReturn("schema1");
        final String tableName = "t1";
        when(rs.getString(eq(3))).thenReturn(tableName);
        when(rs.getString(eq("TABLE_NAME"))).thenReturn(tableName);
        return rs;
    }

    public interface Checker {
        void check(MetadataFactory mf, Connection c, DatabaseMetaData md) throws Exception;
    }
}
