package ru.yandex.wmconsole.periodic;

import java.util.ArrayList;
import java.util.List;

import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.ReadablePeriod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;

import ru.yandex.common.framework.user.UserInfo;
import ru.yandex.common.scheduler.ExecutionContext;
import ru.yandex.common.util.db.LongRowMapper;
import ru.yandex.wmconsole.data.partition.WMCPartition;
import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.service.UserService;
import ru.yandex.wmtools.common.util.SqlUtil;
import ru.yandex.wmtools.common.util.scheduler.timetable.AbstractTaskExecutor;

/**
 * @author avhaliullin
 */
public class CheckRemovedUsersTask extends AbstractTaskExecutor {
    private static final Logger log = LoggerFactory.getLogger(CheckRemovedUsersTask.class);

    private static final String SELECT_UNCOFIRMED_REMOVED_USERS_QUERY =
            "SELECT " +
                    "       user_id " +
                    "   FROM " +
                    "       tbl_removed_users " +
                    "   WHERE " +
                    "       confirmed = 0 " +
                    "   AND " +
                    "       last_check < ? " +
                    "   LIMIT ?";

    private static final String UPDATE_CONFIRM_REMOVED_USERS_QUERY =
            "UPDATE " +
                    "       tbl_removed_users " +
                    "   SET " +
                    "       confirmed = 1 " +
                    "   WHERE " +
                    "       user_id IN (%1$s)";

    private static final String DELETE_CANCEL_REMOVED_USERS_QUERY =
            "DELETE FROM " +
                    "       tbl_removed_users " +
                    "   WHERE " +
                    "       user_id IN (%1$s)";

    private UserService userService;

    private static final int DEFAULT_MAX_USERS_TO_LOAD = 1000;

    private ReadablePeriod recheckAfterPeriod = Days.days(7);

    @Override
    public String runWithRELogging(ExecutionContext context) throws InternalException {
        log.info("Starting to check removed users");
        DateTime lastCheckOlderThan = DateTime.now().minus(recheckAfterPeriod);
        List<Long> users = getJdbcTemplate(WMCPartition.nullPartition()).query(
                SELECT_UNCOFIRMED_REMOVED_USERS_QUERY,
                new LongRowMapper(),
                lastCheckOlderThan.toDate(), DEFAULT_MAX_USERS_TO_LOAD);
        log.info("Loaded {} users to check", users.size());
        List<Long> confirm = new ArrayList<Long>();
        List<Long> cancel = new ArrayList<Long>();
        for (Long userId : users) {
            try {
                UserInfo userInfo = userService.getUserInfo(userId);
                if (userInfo == null) {
                    confirm.add(userId);
                } else {
                    cancel.add(userId);
                }
            } catch (RuntimeException e) {
                log.warn("Failed to check user id " + userId, e);
            }
        }
        String result = String.format("Confirmed %1$d users, cancelled for %2$d users", confirm.size(), cancel.size());
        log.info(result);
        if (!confirm.isEmpty()) {
            getJdbcTemplate(WMCPartition.nullPartition()).update(String.format(
                    UPDATE_CONFIRM_REMOVED_USERS_QUERY,
                    SqlUtil.getCommaSeparatedList(confirm)));
        }
        if (!cancel.isEmpty()) {
            getJdbcTemplate(WMCPartition.nullPartition()).update(String.format(
                    DELETE_CANCEL_REMOVED_USERS_QUERY,
                    SqlUtil.getCommaSeparatedList(cancel)));
        }
        return "Task done. " + result;
    }

    @Required
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    @Required
    public void setRecheckAfterDays(int days) {
        this.recheckAfterPeriod = Days.days(days);
    }
}
