package eu.dnetlib.datasource.publisher.clients;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import com.google.common.collect.Lists;
import eu.dnetlib.datasource.publisher.ApiException;
import eu.dnetlib.datasource.publisher.NotFoundException;
import eu.dnetlib.datasource.publisher.clients.utils.DatasourceFunctions;
import eu.dnetlib.datasource.publisher.model.Datasource;
import org.antlr.stringtemplate.StringTemplate;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;

/**
 * Created by claudio on 25/11/2016.
 */
public class JdbcDatasourceDao {

	private static final Log log = LogFactory.getLog(JdbcDatasourceDao.class);

	@Value("${datasource.publisher.getsingle.sql}")
	private ClassPathResource datasourceDetailsSql;

	@Autowired
	private BasicDataSource dsDataSource;

	public List<String> listIds() throws ApiException {
		final List<String> res = Lists.newArrayList();
		try {
			final String sql = "SELECT id FROM dashboard_ds";

			try (final Connection con = getConn(); final PreparedStatement stm = getStm(sql, con); final ResultSet rs = stm.executeQuery()) {
				while (rs.next()) {
					res.add(rs.getString("id"));
				}
			}
		} catch(SQLException e) {
			throw new ApiException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Error querying datasource ids from database", e);
		}
		return res;
	}

	public Datasource getDatasource(final String id) throws ApiException, NotFoundException {
		try {
			final String sql = obtainQuery(datasourceDetailsSql, id);

			try (final Connection con = getConn(); final PreparedStatement stm = getStm(sql, con); final ResultSet rs = stm.executeQuery()) {
				if (rs.next()) {
					return DatasourceFunctions.toDatasource(rs);
				} else {
					throw new NotFoundException(HttpStatus.NOT_FOUND.value(), String.format("unable to find datasource '%s'", id));
				}
			}
		} catch(SQLException | IOException e) {
			throw new ApiException(HttpStatus.INTERNAL_SERVER_ERROR.value(), String.format("Error querying datasource '%s' from database", id), e);
		}
	}

	private Connection getConn() throws SQLException {
		final Connection conn = dsDataSource.getConnection();
		conn.setAutoCommit(false);
		return conn;
	}

	private PreparedStatement getStm(final String sql, final Connection con) throws SQLException {
		final PreparedStatement stm = con.prepareStatement(sql);
		stm.setFetchSize(10);
		return stm;
	}

	protected String obtainQuery(final Resource template, final String id) throws IllegalArgumentException, IOException {
		final StringTemplate st = new StringTemplate(IOUtils.toString(template.getInputStream()));
		st.setAttribute("id", id);
		final String sql = st.toString();
		log.debug("Generated query: " + sql);
		return sql;
	}

}
