package com.vyserion.lodbot.data.core;

import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;

public class CoreDao
{
    private DataSource datasource;
    private NamedParameterJdbcTemplate template;

    /**
     * Creates a new CoreDao object, with a given data source and creates a JDBC template for this query. 
     * @param datasource The datasource.
     */
    public CoreDao(DataSource datasource)
    {
        this.datasource = datasource;
        template = new NamedParameterJdbcTemplate(datasource);
    }
    
    /**
     * Executes a given queyr against the datasource, without any parameters.
     * @param clazz The class that the response should be cast to.
     * @param sql The SQL query to execute.
     * @return The List of objects from the results of the query.
     */
    public <T, P> List<T> query(Class<T> clazz, String sql)
    {
        BeanPropertyRowMapper<T> mapper = new BeanPropertyRowMapper<>(clazz);
        return template.query(sql, mapper);
    }

    /**
     * Executes a given query against the datasource, with a given set of parameters.
     * @param clazz The class that the response should be cast to.
     * @param sql The SQL query to execute.
     * @param params The parameters to use with the query.
     * @return The List of objects from the results of the query.
     */
    public <T, P> List<T> query(Class<T> clazz, String sql, Map<String, P> params)
    {
        MapSqlParameterSource parameters = new MapSqlParameterSource();
        params.forEach((k, v) -> parameters.addValue(k, v));
        BeanPropertyRowMapper<T> mapper = new BeanPropertyRowMapper<>(clazz);
        return template.query(sql, parameters, mapper);
    }
    
    /**
     * Executes a given procedure against the datasource. 
     * @param procedureName The name of the procedure to execute.
     * @param parameters The parameters for the procedure.
     * @return The Map of returned values from the procedure.
     */
    public Map<String, ?> executeProcedure(String procedureName, Map<String, ?> parameters)
    {
        SimpleJdbcCall call = new SimpleJdbcCall(this.datasource).withSchemaName("lodbot").withProcedureName(procedureName);
        SqlParameterSource callParameters = new MapSqlParameterSource(parameters);
        return call.execute(callParameters);
    }
}