package org.example;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.commons.lang3.RandomStringUtils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

class TestMariaDBIntegerOverflow {

    private static Connection connectionTCPIP;
    private static Connection connectionSocket;

    @BeforeAll
    static void beforeAll() throws SQLException {
        connectionTCPIP = DriverManager.getConnection("jdbc:mariadb://localhost:3306/test-int?user=user&password=password");
        connectionSocket = DriverManager.getConnection("jdbc:mariadb:///test-int?user=user&user=password&localSocket=/tmp/mysql.sock");

        connectionTCPIP.setAutoCommit(true);
        connectionSocket.setAutoCommit(true);

        connectionTCPIP.createStatement().execute("""
                CREATE TABLE IF NOT EXISTS test_table(
                                    int_column        int default 100,
                                    mediumtext_column mediumtext null
                                )collate = utf8mb3_bin;
                              """);


    }

    @AfterAll
    static void afterAll() throws SQLException {
        connectionTCPIP.createStatement().execute("DROP TABLE IF  EXISTS test_table;");
        connectionTCPIP.close();
        connectionSocket.close();
    }

    @BeforeEach
    void setup() throws SQLException {
        connectionTCPIP.createStatement().execute("delete from test_table");
    }

    @ParameterizedTest
    @ValueSource(ints = { 1000, 10000, 20000, 30000 })
    void test(int stringLength) throws SQLException {
        insertRow(connectionTCPIP, stringLength);
        check(connectionTCPIP, "tcp/ip", stringLength);
        check(connectionSocket, "socket", stringLength);
    }


    private void check(Connection connection, String type, int expectedLength) throws SQLException {
        ResultSet resultSet = connection.createStatement().executeQuery("select * from test_table");
        if (resultSet.next()) {
            int intValue = resultSet.getInt("int_column");
            int size = resultSet.getString("mediumtext_column").length();

            assertEquals(expectedLength, size, "Wrong int type=" + type);
            assertEquals(100, intValue, "Wrong string length" + type);
        } else {
            fail();
        }
    }

    private void insertRow(Connection connection, long noChars) throws SQLException {
        PreparedStatement preparedStatement = connection.prepareStatement("insert into test_table (mediumtext_column) values(?)");
        preparedStatement.setString(1, RandomStringUtils.randomAlphabetic((int) noChars));
        preparedStatement.executeUpdate();
    }

}