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.NullSource;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.time.LocalDate;
import java.time.LocalDateTime;

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

class PreparedStatementUtilsTest {

    @Mock
    PreparedStatement preparedStatement;

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

    @ParameterizedTest
    @NullSource
    void whenNullValue_getDateFromLocalDate_shouldReturnNull(LocalDate value) {
        assertNull(PreparedStatementUtils.getDateFromLocalDate(value));
    }

    @Test
    void whenValueIsAvailable_getDateFromLocalDate_shouldReturnLocalDate() {
        var value = LocalDate.of(2022,1,1);

        var result = PreparedStatementUtils.getDateFromLocalDate(value);

        assertEquals(Date.valueOf("2022-01-01"), result);
    }

    @ParameterizedTest
    @NullSource
    void whenNullValue_getTimestampFromLocalDateTime_shouldReturnNull(LocalDateTime value) {
        assertNull(PreparedStatementUtils.getTimestampFromLocalDateTime(value));
    }

    @Test
    void whenValueIsAvailable_getTimestampFromLocalDateTime_shouldReturnLocalDate() {
        var value = LocalDateTime.of(2022,1,1, 15,15,6);

        var result = PreparedStatementUtils.getTimestampFromLocalDateTime(value);

        assertEquals(Timestamp.valueOf("2022-01-01 15:15:06.000"), result);
    }

    @ParameterizedTest
    @NullSource
    void whenNullValue_setIntValue_shouldSetNull(Integer value) throws SQLException {
        PreparedStatementUtils.setIntValue(preparedStatement, 1, value);

        Mockito.verify(preparedStatement, Mockito.times(1)).setNull(1, Types.INTEGER);
    }

    @Test
    void whenValueIsAvailable_setIntValue_shouldSetIntWithValue() throws SQLException {
        var value = 1;
        PreparedStatementUtils.setIntValue(preparedStatement, 1, value);

        Mockito.verify(preparedStatement, Mockito.times(1)).setInt(1, value);
    }

    @ParameterizedTest
    @NullSource
    void whenNullValue_setDoubleValue_shouldSetNull(Double value) throws SQLException {
        PreparedStatementUtils.setDoubleValue(preparedStatement, 1, value);

        Mockito.verify(preparedStatement, Mockito.times(1)).setNull(1, Types.DOUBLE);
    }

    @Test
    void whenValueIsAvailable_setDoubleValue_shouldSetDoubleWithValue() throws SQLException {
        var value = 1.2;
        PreparedStatementUtils.setDoubleValue(preparedStatement, 1, value);

        Mockito.verify(preparedStatement, Mockito.times(1)).setDouble(1, value);
    }
}
