package org.simpleflatmapper.jdbc.spring.test;

import org.junit.Test;
import org.simpleflatmapper.jdbc.SqlTypeColumnProperty;
import org.simpleflatmapper.jdbc.spring.JdbcTemplateMapperFactory;
import org.simpleflatmapper.jdbc.spring.SqlParameterSourceFactory;
import org.simpleflatmapper.test.beans.DbObject;
import org.simpleflatmapper.map.property.ConstantValueProperty;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;

import java.sql.Timestamp;
import java.sql.Types;

//IFJAVA8_START
import java.time.Instant;
//IFJAVA8_END
import java.util.Arrays;

import static org.junit.Assert.assertEquals;

public class SqlParameterSourceTest {

    //IFJAVA8_START
    @Test
    public void testInstantShouldBeTimestampType() {
        String sql = "INSERT INTO table VALUES(:instant)";

        SqlParameterSourceFactory<ObjectWithInstant> sqlParameters =
                JdbcTemplateMapperFactory
                        .newInstance()
                        .newSqlParameterSourceFactory(ObjectWithInstant.class, sql);

        
        ObjectWithInstant data = new ObjectWithInstant(Instant.now());
        
        SqlParameterSource parameterSource = sqlParameters.newSqlParameterSource(data);

        assertEquals(Types.TIMESTAMP, parameterSource.getSqlType("instant"));
        assertEquals(new Timestamp(data.instant.toEpochMilli()), parameterSource.getValue("instant"));

    }

    @Test
    public void testSpecifySqlType() {
        String sql = "INSERT INTO table VALUES(:instant)";

        SqlParameterSourceFactory<ObjectWithObject> sqlParameters =
                JdbcTemplateMapperFactory
                        .newInstance()
                        .addColumnProperty("instant", SqlTypeColumnProperty.of(Types.TIMESTAMP))
                        .newSqlParameterSourceFactory(ObjectWithObject.class, sql);


        ObjectWithObject data = new ObjectWithObject(Instant.now());

        SqlParameterSource parameterSource = sqlParameters.newSqlParameterSource(data);

        assertEquals(Types.TIMESTAMP, parameterSource.getSqlType("instant"));
        assertEquals(new Timestamp(((Instant)data.instant).toEpochMilli()), parameterSource.getValue("instant"));

    }
    
    public class ObjectWithInstant {
        public final Instant instant;

        public ObjectWithInstant(Instant instant) {
            this.instant = instant;
        }
    }

    public class ObjectWithObject {
        public final Object instant;

        public ObjectWithObject(Object instant) {
            this.instant = instant;
        }
    }
    //IFJAVA8_END
    @Test
    public void testParseSql() {
        String sql = "INSERT INTO table VALUES(:id, :name, :email)";

        SqlParameterSourceFactory<DbObject> sqlParameters =
                JdbcTemplateMapperFactory.newInstance().newSqlParameterSourceFactory(DbObject.class, sql);

        testMapping(sqlParameters);
    }

    protected void testMapping(SqlParameterSourceFactory<DbObject> sqlParameterSourceFactory) {
        DbObject dbObject = getDbObject();

        SqlParameterSource parameterSource = sqlParameterSourceFactory.newSqlParameterSource(dbObject);

        assertEquals(12345l, parameterSource.getValue("id"));
        assertEquals("name", parameterSource.getValue("name"));
        assertEquals("email", parameterSource.getValue("email"));

        assertEquals(Types.BIGINT, parameterSource.getSqlType("id"));
        assertEquals(Types.VARCHAR, parameterSource.getSqlType("name"));

        assertEquals(null, parameterSource.getTypeName("id"));
        assertEquals(null, parameterSource.getTypeName("name"));
    }

    protected DbObject getDbObject() {
        DbObject dbObject = new DbObject();
        dbObject.setId(12345);
        dbObject.setName("name");
        dbObject.setEmail("email");
        return dbObject;
    }


    @Test
    public void testDynamicParams(){
        SqlParameterSourceFactory<DbObject> parameterSourceFactory =
                JdbcTemplateMapperFactory.newInstance().newSqlParameterSourceFactory(DbObject.class);
        testMapping(parameterSourceFactory);
    }

    @Test
    public void testAlias(){
        SqlParameterSourceFactory<DbObject> parameterSourceFactory =
                JdbcTemplateMapperFactory.newInstance().addAlias("e", "email").newSqlParameterSourceFactory(DbObject.class);
        DbObject dbObject = getDbObject();

        SqlParameterSource parameterSource = parameterSourceFactory.newSqlParameterSource(dbObject);

        assertEquals(12345l, parameterSource.getValue("id"));
        assertEquals("name", parameterSource.getValue("name"));
        assertEquals("email", parameterSource.getValue("e"));
        assertEquals("email", parameterSource.getValue("email"));

    }


    @Test
    public void testSource() {
        SqlParameterSourceFactory<DbObject> parameterSourceFactory =
                JdbcTemplateMapperFactory.newInstance().newSqlParameterSourceFactory(DbObject.class);

        DbObject[] dbObjects = new DbObject[10];
        for(int i = 0; i < dbObjects.length; i++ ) {
            dbObjects[i] = new DbObject();
            dbObjects[i].setId(i);
        }

        validate(parameterSourceFactory.newSqlParameterSources(dbObjects));
        validate(parameterSourceFactory.newSqlParameterSources(Arrays.asList(dbObjects)));

    }

    private void validate(SqlParameterSource[] sqlParameterSources) {
        for(int i = 0; i < sqlParameterSources.length; i++) {
            assertEquals((long)i, sqlParameterSources[i].getValue("id"));
        }
    }

    @Test
    public void testConstantValue() {
        SqlParameterSourceFactory<DbObject> parameterSourceFactory =
                JdbcTemplateMapperFactory
                        .newInstance()
                        .addColumnProperty("id", new ConstantValueProperty<Long>(-3l, Long.class))
                        .newSqlParameterSourceFactory(DbObject.class);

        SqlParameterSource parameterSource = parameterSourceFactory.newSqlParameterSource(new DbObject());

        assertEquals(-3l, parameterSource.getValue("id"));

    }
}

@@ -436,16 +436,38 @@
 ource;%0A%0A
+import java.sql.Date;%0A
 import j
@@ -565,16 +565,48 @@
 VA8_END%0A
+import java.time.ZonedDateTime;%0A
 import j
@@ -2243,24 +2243,1052 @@
 nstant%22));%0A%0A
+    %7D%0A    %0A    @Test%0A    public void testIssue589() %7B%0A        SqlParameterSourceFactory%3CIssue589%3E parameterSourceFactory = JdbcTemplateMapperFactory.newInstance()%0A                .ignorePropertyNotFound()%0A                .addAlias(%22timestamp_%22, %22timestamp%22)%0A                .addColumnProperty(%22timestamp_%22, SqlTypeColumnProperty.of(Types.TIMESTAMP))%0A                .newSqlParameterSourceFactory(Issue589.class);%0A        %0A        ZonedDateTime now = ZonedDateTime.now();%0A        Issue589 issue589 = new Issue589(now);%0A%0A        SqlParameterSource sqlParameterSource = parameterSourceFactory.newSqlParameterSource(issue589);%0A        %0A        assertEquals(Types.TIMESTAMP, sqlParameterSource.getSqlType(%22timestamp_%22));%0A        assertEquals(new Timestamp(Date.from(now.toInstant()).getTime()), sqlParameterSource.getValue(%22timestamp_%22));%0A    %7D%0A    %0A    public static class Issue589 %7B%0A        public final ZonedDateTime timestamp;%0A%0A        public Issue589(ZonedDateTime timestamp) %7B%0A            this.timestamp = timestamp;%0A        %7D%0A
     %7D%0A    %0A 

add test for issue #589