package ru.yandex.wmconsole.service.dao;

import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import ru.yandex.common.util.collections.Cu;
import ru.yandex.wmconsole.data.MainMirrorStateEnum;
import ru.yandex.wmconsole.data.info.BriefHostInfo;
import ru.yandex.wmconsole.data.mirror.MirrorGroupActionEnum;
import ru.yandex.wmconsole.data.mirror.MirrorGroupChangeRequest;
import ru.yandex.wmconsole.data.mirror.MirrorGroupChangeStateEnum;
import ru.yandex.wmconsole.data.partition.WMCPartition;
import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.service.AbstractDbService;
import ru.yandex.wmtools.common.sita.SitaMirroringActionStatusEnum;
import ru.yandex.wmtools.common.sita.SitaMirroringHostStatusEnum;
import ru.yandex.wmtools.common.util.SqlUtil;

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

/**
 * User: azakharov
 * Date: 10.01.14
 * Time: 13:40
 */
public class TblMainMirrorRequestsDao extends AbstractDbService {

    public void saveRequestEx(final BriefHostInfo briefHostInfo, final MirrorGroupChangeRequest r) throws InternalException {
        String query =
                "REPLACE INTO tbl_main_mirror_requests " +
                        "   (host_id, state, action_id, desired_main, created_at, modified_at, notified, user_id, attempts, action_status, host1, status1, host2, status2, old_main) " +
                        "VALUES " +
                        "   (?, ?, ?, ?, ?, NOW(), 0, ?, ?, ?, ?, ?, ?, ?, ?)";
        Integer actionStatus = r.getActionInfo().getActionStatus() != null ? r.getActionInfo().getActionStatus().value() : null;
        Integer status1 = r.getActionInfo().getHostStatus1() != null ? r.getActionInfo().getHostStatus1().value() : null;
        Integer status2 = r.getActionInfo().getHostStatus2() != null ? r.getActionInfo().getHostStatus2().value() : null;

        getJdbcTemplate(WMCPartition.nullPartition()).update(
                query, briefHostInfo.getId(), r.getState().value(), r.getAction().value(),
                r.getDesiredMain(), r.getCreateDate(), r.getUserId(), r.getAttempts(),
                actionStatus, r.getActionInfo().getHostName1(), status1, r.getActionInfo().getHostName2(), status2,
                r.getOldMainMirrorName());
    }

    public List<MirrorGroupChangeRequest> getRequests(final BriefHostInfo briefHostInfo) throws InternalException {
        String query =
                "SELECT " +
                "   host_id, state, action_id, desired_main, created_at, modified_at, notified, user_id, action_status, host1, status1, host2, status2, attempts, old_main " +
                "FROM " +
                "   tbl_main_mirror_requests " +
                "WHERE host_id = ?";

        return getJdbcTemplate(WMCPartition.nullPartition()).query(
                query, m, briefHostInfo.getId());
    }

    public List<MirrorGroupChangeRequest> getActualRerankRequestsForHosts(final List<Long> hostIds) throws InternalException {
        List<Integer> activeStates = MirrorGroupChangeStateEnum.getListOfDeclinedStates();

        String query =
                "SELECT " +
                        "   host_id, state, action_id, desired_main, created_at, modified_at, notified, user_id, action_status, host1, status1, host2, status2, attempts, old_main " +
                        "FROM " +
                        "   tbl_main_mirror_requests " +
                        "WHERE host_id IN (" + SqlUtil.createQuestionMarks(hostIds.size()) + ") " +
                        "AND state NOT IN (" + SqlUtil.createQuestionMarks(activeStates.size()) + ") " +
                        "AND action_id = " + MirrorGroupActionEnum.RERANGE.value() + " ";

        if (hostIds.isEmpty()) {
            return Collections.emptyList();
        }

        ArrayList<Object> params = new ArrayList<>(hostIds.size() + activeStates.size());
        params.addAll(hostIds);
        params.addAll(activeStates);

        return getJdbcTemplate(WMCPartition.nullPartition()).query(
                query, m, params.toArray());
    }

    public MirrorGroupChangeRequest getFirstWaitingRequest() throws InternalException {
        String query = "SELECT " +
                       "    host_id, state, action_id, desired_main, created_at, modified_at, notified, user_id, action_status, host1, status1, host2, status2, attempts, old_main " +
                       "FROM " +
                       "    tbl_main_mirror_requests " +
                       "WHERE state IN (" + MirrorGroupChangeStateEnum.NEW.value() + ", " +
                                            MirrorGroupChangeStateEnum.NEED_RECHECK.value() + ") " +
                       "AND " +
                        "   attempts > 0 " +
                       "ORDER BY state ASC, attempts DESC LIMIT 1";
        List<MirrorGroupChangeRequest> res = getJdbcTemplate(WMCPartition.nullPartition()).query(query, m);
        return Cu.firstOrNull(res);
    }

    public void updateState(MirrorGroupChangeRequest request) throws InternalException {
        final String query = "UPDATE tbl_main_mirror_requests SET state = ?, attempts = ? WHERE host_id = ?";
        getJdbcTemplate(WMCPartition.nullPartition()).update(
                query, request.getState().value(), request.getAttempts(), request.getHostId());
    }

    public void updateState2(MirrorGroupChangeRequest r) throws InternalException {
        final String query =
                "UPDATE tbl_main_mirror_requests " +
                "SET state = ?, attempts = ?, action_status = ?, host1 = ?, status1 = ?, host2 = ?, status2 = ? "+
                "WHERE host_id = ?";
        Integer actionStatus = r.getActionInfo().getActionStatus() != null ? r.getActionInfo().getActionStatus().value() : null;
        Integer status1 = r.getActionInfo().getHostStatus1() != null ? r.getActionInfo().getHostStatus1().value() : null;
        Integer status2 = r.getActionInfo().getHostStatus2() != null ? r.getActionInfo().getHostStatus2().value() : null;

        getJdbcTemplate(WMCPartition.nullPartition()).update(query,
                r.getState().value(),
                r.getAttempts(),
                actionStatus,
                r.getActionInfo().getHostName1(),
                status1,
                r.getActionInfo().getHostName2(),
                status2,
                r.getHostId());
    }

    public void markNotified(BriefHostInfo hostInfo) throws InternalException {
        final String query =
                "UPDATE tbl_main_mirror_requests SET notified = true WHERE host_id = ? AND state IN (?, ?)";
        getJdbcTemplate(WMCPartition.nullPartition()).update(query, hostInfo.getId(),
                MirrorGroupChangeStateEnum.DECLINED.value(), MirrorGroupChangeStateEnum.RECHECK_DECLINED.value());
    }

    public void deleteRequest(BriefHostInfo hostInfo) throws InternalException {
        final String query =
                "DELETE FROM tbl_main_mirror_requests WHERE host_id = ?";
        getJdbcTemplate(WMCPartition.nullPartition()).update(query, hostInfo.getId());
    }

    private static final ParameterizedRowMapper<MirrorGroupChangeRequest> m = new ParameterizedRowMapper<MirrorGroupChangeRequest>() {
        @Override
        public MirrorGroupChangeRequest mapRow(ResultSet rs, int rowNum) throws SQLException {
            final long hostId = rs.getLong("host_id");
            final MirrorGroupChangeStateEnum status = MirrorGroupChangeStateEnum.R.fromValueOrNull(rs.getInt("state"));
            final MirrorGroupActionEnum action = MirrorGroupActionEnum.R.fromValueOrNull(rs.getInt("action_id"));
            final boolean isNotified = rs.getBoolean("notified");
            final long userId = rs.getLong("user_id");
            final Date modificationDate = SqlUtil.safeGetTimestamp(rs, "modified_at");
            final Date createDate = SqlUtil.safeGetTimestamp(rs, "created_at");
            final String desiredMain = rs.getString("desired_main");
            int actionStatusValue = rs.getInt("action_status");
            final SitaMirroringActionStatusEnum actionStatus =
                    rs.wasNull() ? null : SitaMirroringActionStatusEnum.R.fromValueOrNull(actionStatusValue);
            final String hostName1 = SqlUtil.getStringNullable(rs, "host1");
            int val1 = rs.getInt("status1");
            final SitaMirroringHostStatusEnum hostStatus1 =
                    rs.wasNull() ? null : SitaMirroringHostStatusEnum.R.fromValueOrNull(val1);
            final String hostName2 = SqlUtil.getStringNullable(rs, "host2");
            int val2 = rs.getInt("status2");
            final SitaMirroringHostStatusEnum hostStatus2 =
                    rs.wasNull() ? null : SitaMirroringHostStatusEnum.R.fromValueOrNull(val2);
            final Integer attempts = SqlUtil.getIntNullable(rs, "attempts");
            final String oldMainMirrorName = SqlUtil.getStringNullable(rs, "old_main");
            return new MirrorGroupChangeRequest(
                    hostId, userId, createDate, modificationDate, desiredMain, action, status, oldMainMirrorName, actionStatus, hostName1, hostStatus1, hostName2, hostStatus2, attempts, isNotified
            );
        }
    };
}
