package org.mte.numecoeval.common.utils;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullAndEmptySource;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.LocalDate;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.Mockito.when;

class ResultSetUtilsTest {

    @Mock
    ResultSet resultSet;

    @BeforeEach
    void setup() {
        MockitoAnnotations.openMocks(this);
    }

    @ParameterizedTest
    @NullAndEmptySource
    void whenColumnIsNull_getMethodsUsingCheckColumnInResultSet_shouldReturn(String columnName) throws SQLException {
        assertNull(ResultSetUtils.getLocalDate(resultSet, columnName));
        assertNull(ResultSetUtils.getLocalDateTime(resultSet, columnName));
        assertNull(ResultSetUtils.getFloat(resultSet, columnName));
        assertNull(ResultSetUtils.getInteger(resultSet, columnName));
        assertNull(ResultSetUtils.getDouble(resultSet, columnName));
    }

    @Test
    void whenResultSetIsNull_getMethodsUsingCheckColumnInResultSet_shouldReturn() throws SQLException {
        var columnName = "colonne";
        assertNull(ResultSetUtils.getLocalDate(null, columnName));
        assertNull(ResultSetUtils.getLocalDateTime(null, columnName));
        assertNull(ResultSetUtils.getFloat(null, columnName));
        assertNull(ResultSetUtils.getInteger(null, columnName));
        assertNull(ResultSetUtils.getDouble(null, columnName));
    }

    @Test
    void whenValueIsAvailable_getLocalDate_shouldReturnLocalDate() throws SQLException {
        var columnName = "test";
        var dateTime = 1683310020L;
        when(resultSet.getString(columnName)).thenReturn(new Date(dateTime).toString());
        when(resultSet.getDate(columnName)).thenReturn(new Date(dateTime));

        var result = ResultSetUtils.getLocalDate(resultSet, columnName);

        assertEquals(LocalDate.of(1970,1,20), result);
    }

    @Test
    void whenValueIsAvailable_getLocalDateTime_shouldReturnLocalDate() throws SQLException {
        var columnName = "test";
        var dateTime = 1683310020L;
        when(resultSet.getString(columnName)).thenReturn(new Date(dateTime).toString());
        var originalTimestamp = new Timestamp(dateTime);
        when(resultSet.getTimestamp(columnName)).thenReturn(originalTimestamp);

        var result = ResultSetUtils.getLocalDateTime(resultSet, columnName);

        assertEquals(originalTimestamp.toLocalDateTime(), result);
    }

    @Test
    void whenValueIsAvailable_getFloat_shouldReturnLocalDate() throws SQLException {
        var columnName = "test";
        var value = Float.valueOf(6.6f);
        when(resultSet.getString(columnName)).thenReturn(value.toString());
        when(resultSet.getFloat(columnName)).thenReturn(value);

        var result = ResultSetUtils.getFloat(resultSet, columnName);

        assertEquals(value, result);
    }

    @Test
    void whenValueIsAvailable_getDouble_shouldReturnLocalDate() throws SQLException {
        var columnName = "test";
        var value = Double.valueOf(6.6);
        when(resultSet.getString(columnName)).thenReturn(value.toString());
        when(resultSet.getDouble(columnName)).thenReturn(value);

        var result = ResultSetUtils.getDouble(resultSet, columnName);

        assertEquals(value, result);
    }

    @Test
    void whenValueIsAvailable_getInteger_shouldReturnLocalDate() throws SQLException {
        var columnName = "test";
        var value = Integer.valueOf(6);
        when(resultSet.getString(columnName)).thenReturn(value.toString());
        when(resultSet.getInt(columnName)).thenReturn(value);

        var result = ResultSetUtils.getInteger(resultSet, columnName);

        assertEquals(value, result);
    }
}
