package eu.dnetlib.openaire.info;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;

import javax.sql.DataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import eu.dnetlib.DnetOpenaireExporterProperties;

/**
 * Created by alessia on 29/04/2020
 *
 * Get and set info dates via JDBC. Dates are expected to be in a table named 'info' with two columns: key - see JdbcInfoDao.DATE_INFO enum
 * value - the date (LocalDate, no time)
 *
 */
@Component
@ConditionalOnProperty(value = "openaire.exporter.enable.info", havingValue = "true")
public class JdbcInfoDaoImpl implements JdbcInfoDao {

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

	@Autowired
	private DnetOpenaireExporterProperties config;

	@Autowired
	private DataSource dataSource;

	@Override
	@Cacheable("info")
	public LocalDate getDate(final DATE_INFO dateInfo) {
		final String sql = "SELECT value FROM info WHERE key=?";

		LocalDate date = null;
		try (final Connection con = getConn(); final PreparedStatement stm = getStm(sql, con, dateInfo.name()); final ResultSet rs = getRs(stm)) {
			log.info("loading info " + dateInfo + " Query: " + stm.toString());
			if (rs.next()) {
				date = rs.getObject("value", LocalDate.class);
			}
		} catch (final SQLException e) {
			throw new RuntimeException(e);
		}

		return date;
	}

	@Override
	@CacheEvict(cacheNames = {
		"info"
	}, allEntries = true)
	@Scheduled(fixedDelayString = "${openaire.exporter.cache.ttl}")
	public void dropCache() {
		log.debug("dropped info cache");
	}

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

	private PreparedStatement getStm(final String sql, final Connection con, final String param) throws SQLException {
		final PreparedStatement stm = con.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY);
		stm.setString(1, param);
		stm.setFetchSize(config.getJdbc().getMaxRows());
		return stm;
	}

	private ResultSet getRs(final PreparedStatement stm) throws SQLException {
		final ResultSet rs = stm.executeQuery();
		rs.setFetchSize(config.getJdbc().getMaxRows());
		return rs;
	}

}
