package ru.yandex.wmconsole.service;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.transaction.TransactionStatus;

import ru.yandex.wmconsole.data.NotificationTypeEnum;
import ru.yandex.wmconsole.data.info.UsersHostsInfo;
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;
import ru.yandex.wmtools.common.util.SqlUtil;

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

    private static final String SELECT_UNPROCESSED_HOSTS_PACK_QUERY =
            "SELECT " +
                        "host_id " +
                    "FROM " +
                        "tbl_notification_concurrency_errorsgrow " +
                    "WHERE " +
                        "DATEDIFF(?, last_update) > 1 " +
                    "OR " +
                        "last_update IS NULL " +
                    "LIMIT 0, ? " +
                    "FOR UPDATE";

    private static final String UPDATE_UNPROCESSED_HOSTS_QUERY =
            "UPDATE " +
                        "tbl_notification_concurrency_errorsgrow " +
                    "SET " +
                        "last_update = ? " +
                    "WHERE " +
                        "host_id IN (%s)";

    private CollectConcurrencyService collectConcurrencyService;
    private UsersHostsService usersHostsService;

    private static final ParameterizedRowMapper<Long> HOST_ID_MAPPER =
            new ParameterizedRowMapper<Long>() {
                private static final String FIELD_HOST_ID = "host_id";

                @Override
                public Long mapRow(ResultSet resultSet, int rowNum) throws SQLException {
                    return resultSet.getLong(FIELD_HOST_ID);
                }
            };

    public List<UsersHostsInfo> getUnprocessedHosts() throws InternalException, UserException {
        final long packMaxSize = 50000;

        final Date lastUpdate = collectConcurrencyService.getTypeUpdateDate(NotificationTypeEnum.ERRORS_GROW);
        final List<Long> result = new ArrayList<Long>((int) packMaxSize);

        getServiceTransactionTemplate(WMCPartition.nullPartition()).executeInService(new ServiceTransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) throws InternalException {
                log.debug("Success select logging: UNPROCESSED_HOSTS_PACK_QUERY");
                List<Long> hosts = getJdbcTemplate(WMCPartition.nullPartition()).query(
                        SELECT_UNPROCESSED_HOSTS_PACK_QUERY,
                        HOST_ID_MAPPER,
                        lastUpdate,
                        packMaxSize
                );

                if (hosts != null && hosts.size() != 0) {
                    log.debug("Grabbed unprocessed " + hosts.size() + " hosts");

                    String queryString = String.format(UPDATE_UNPROCESSED_HOSTS_QUERY, SqlUtil.getCommaSeparatedList(hosts));
                    log.debug("Success update logging: UNPROCESSED_HOSTS_UPDATE_STRING");
                    getJdbcTemplate(WMCPartition.nullPartition()).update(queryString, lastUpdate);

                    result.addAll(hosts);
                }
            }
        });

        return usersHostsService.getUsersHostsInfoList(result);
    }

    @Required
    public void setCollectConcurrencyService(CollectConcurrencyService collectConcurrencyService) {
        this.collectConcurrencyService = collectConcurrencyService;
    }

    @Required
    public void setUsersHostsService(UsersHostsService usersHostsService) {
        this.usersHostsService = usersHostsService;
    }
}
