package ru.yandex.wmconsole.service;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.transaction.TransactionStatus;

import ru.yandex.wmconsole.data.ErrorsGrowNotificationInfo;
import ru.yandex.wmconsole.data.partition.WMCPartition;
import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.error.UserException;
import ru.yandex.wmtools.common.service.AbstractDbService;
import ru.yandex.wmtools.common.util.ServiceTransactionCallbackWithoutResult;

/**
 * @author Andrey Mima (amima@yandex-team.ru)
 */
public class ErrorsGrowService extends AbstractDbService {
    private static final Logger log = LoggerFactory.getLogger(ErrorsGrowService.class);

    private static final String INSERT_ERRORS_GROW_QUERY =
            "INSERT INTO " +
                        "tbl_notification_errorsgrow (host_id, percent, receive_time) " +
                    "VALUES (?, ?, ?)";

    private static final String SELECT_ERRORS_GROW_QUERY =
            "SELECT " +
                        "host_id, percent, receive_time " +
                    "FROM " +
                        "tbl_notification_errorsgrow " +
                    "WHERE " +
                        "errorsgrow_id = ?";

    private static final String INSERT_IGNORE_NEW_HOSTS_QUERY =
            "INSERT IGNORE INTO tbl_notification_concurrency_errorsgrow (host_id) " +
                    "SELECT DISTINCT(tbl_users_hosts.host_id) FROM " +
                    "tbl_users_hosts LEFT JOIN tbl_notification_concurrency_errorsgrow " +
                    "ON tbl_users_hosts.host_id = tbl_notification_concurrency_errorsgrow.host_id " +
                    "WHERE tbl_notification_concurrency_errorsgrow.host_id IS NULL";

    private static final ParameterizedRowMapper<ErrorsGrowNotificationInfo> ERRORS_GROW_NOTIFICATION_MAPPER =
            new ParameterizedRowMapper<ErrorsGrowNotificationInfo>() {
                private static final String FIELD_HOST_ID = "host_id";
                private static final String FIELD_PERCENT = "percent";
                private static final String FIELD_RECEIVE_TIME = "receive_time";

                @Override
                public ErrorsGrowNotificationInfo mapRow(ResultSet resultSet, int rowNum) throws SQLException {
                    Long hostId = resultSet.getLong(FIELD_HOST_ID);
                    Integer percent = resultSet.getInt(FIELD_PERCENT);
                    Date receiveTime = resultSet.getDate(FIELD_RECEIVE_TIME);
                    return new ErrorsGrowNotificationInfo(hostId, percent, receiveTime);
                }
            };

    public Long addErrorsGrowNotification(final Long hostId, final Integer percent, final Date receiveTime) throws InternalException {
        GeneratedKeyHolder generatedKeyHolder = new GeneratedKeyHolder();
        PreparedStatementCreator psc = new PreparedStatementCreator() {
            @Override
            public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
                PreparedStatement ps = connection.prepareStatement(INSERT_ERRORS_GROW_QUERY,
                        Statement.RETURN_GENERATED_KEYS);
                ps.setLong(1, hostId);
                ps.setInt(2, percent);
                ps.setTimestamp(3, new Timestamp(receiveTime.getTime()));
                return ps;
            }
        };

        getJdbcTemplate(WMCPartition.nullPartition()).getJdbcOperations().update(psc, generatedKeyHolder);
        return generatedKeyHolder.getKey().longValue();
    }

    public ErrorsGrowNotificationInfo getErrorsGrowNotification(Long errorsGrowNotificationId) throws InternalException {
        return getJdbcTemplate(WMCPartition.nullPartition()).queryForObject(
                SELECT_ERRORS_GROW_QUERY,
                ERRORS_GROW_NOTIFICATION_MAPPER,
                errorsGrowNotificationId
        );
    }

    public void refreshConcurrentHosts() throws UserException, InternalException {
        getServiceTransactionTemplate(WMCPartition.nullPartition()).executeInService(new ServiceTransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) throws InternalException {
                log.debug("Success select logging: REFRESH_CONCURRENT_HOSTS_SELECT_QUERY");
                getJdbcTemplate(WMCPartition.nullPartition()).update(INSERT_IGNORE_NEW_HOSTS_QUERY);
            }
        });
    }
}
