package ru.yandex.wmconsole.service;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
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 ru.yandex.common.framework.pager.Pager;
import ru.yandex.wmconsole.data.MainMirrorRequestStateEnum;
import ru.yandex.wmconsole.data.MainMirrorStateEnum;
import ru.yandex.wmconsole.data.info.MainMirrorRequestHistoryInfo;
import ru.yandex.wmconsole.data.partition.WMCPartition;
import ru.yandex.wmtools.common.data.info.WMUserInfo;
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.service.UserInfoService;
import ru.yandex.wmtools.common.util.SqlUtil;
import ru.yandex.wmtools.common.util.TimeFilter;

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

    private static final String FIELD_HOST_ID = "host_id";
    private static final String FIELD_HOST_NAME = "host_name";
    private static final String FIELD_USER_ID = "user_id";
    private static final String FIELD_IS_WWW = "is_www";
    private static final String FIELD_STATE = "state";
    private static final String FIELD_CREATED_AT = "created_at";
    private static final String FIELD_MODIFIED_AT = "modified_at";

    private static final String INSERT_REQUEST_QUERY =
            "INSERT INTO tbl_www_main_mirror_history " +
                    "       (host_id, user_id, is_www, state, created_at, modified_at) " +
                    "   SELECT " +
                    "       host_id, " +
                    "       user_id, " +
                    "       is_www, " +
                    "       state, " +
                    "       created_at, " +
                    "       modified_at " +
                    "   FROM " +
                    "       tbl_www_main_mirror " +
                    "   WHERE " +
                    "       host_id = ? ";

    private static final String SELECT_REQUESTS_HISTORY_COUNT_QUERY =
            "SELECT " +
                    "       count(*) AS count " +
                    "   FROM " +
                    "       tbl_www_main_mirror_history wmmh " +
                    "   JOIN " +
                    "       tbl_hosts h " +
                    "   USING(host_id) " +
                    "   WHERE " +
                    "       TRUE " +
                    "       %1$s " +
                    "       %2$s " +
                    "       %3$s " +
                    "       %4$s " +
                    "       %5$s ";

    private static final String SELECT_REQUESTS_HISTORY_QUERY =
            "SELECT " +
                    "       wmmh.host_id AS " + FIELD_HOST_ID + ", " +
                    "       wmmh.user_id AS " + FIELD_USER_ID + ", " +
                    "       wmmh.is_www AS " + FIELD_IS_WWW + ", " +
                    "       wmmh.state AS " + FIELD_STATE + ", " +
                    "       wmmh.created_at AS " + FIELD_CREATED_AT + ", " +
                    "       wmmh.modified_at AS " + FIELD_MODIFIED_AT + ", " +
                    "       h.name AS " + FIELD_HOST_NAME +
                    "   FROM " +
                    "       tbl_www_main_mirror_history wmmh " +
                    "   JOIN " +
                    "       tbl_hosts h" +
                    "   USING(host_id) " +
                    "   WHERE " +
                    "       TRUE " +
                    "       %1$s " +
                    "       %2$s " +
                    "       %3$s " +
                    "       %4$s " +
                    "       %5$s " +
                    "   ORDER BY " + FIELD_CREATED_AT + " DESC " +
                    "   %6$s ";

    private UserInfoService userInfoService;

    private final ParameterizedRowMapper<MainMirrorRequestHistoryInfo> mapper = new ParameterizedRowMapper<MainMirrorRequestHistoryInfo>() {
        @Override
        public MainMirrorRequestHistoryInfo mapRow(ResultSet rs, int i) throws SQLException {
            WMUserInfo userInfo = null;
            long userId = rs.getLong(FIELD_USER_ID);
            try {
                userInfo = userInfoService.getUserInfo(userId);
            } catch (InternalException e) {
                log.warn("Can't get user info for userId " + rs.getLong(FIELD_USER_ID), e);
            } catch (UserException e) {
                log.warn("Can't get user info for userId " + rs.getLong(FIELD_USER_ID), e);
            }
            return new MainMirrorRequestHistoryInfo(
                    MainMirrorRequestStateEnum.R.fromValueOrNull(rs.getInt(FIELD_STATE)),
                    MainMirrorStateEnum.R.fromValueOrNull(rs.getInt(FIELD_IS_WWW)),
                    rs.getTimestamp(FIELD_CREATED_AT),
                    rs.getTimestamp(FIELD_MODIFIED_AT),
                    rs.getLong(FIELD_HOST_ID),
                    userInfo,
                    rs.getString(FIELD_HOST_NAME));
        }
    };

    public void storeRequest(long hostId) throws InternalException {
        getJdbcTemplate(WMCPartition.nullPartition()).update(INSERT_REQUEST_QUERY, hostId);
    }

    public List<MainMirrorRequestHistoryInfo> getHistory(Pager pager,
                                                         TimeFilter creationDateFilter,
                                                         TimeFilter modifyingDateFilter,
                                                         String hostNameFilter,
                                                         MainMirrorRequestStateEnum requestStateFilter,
                                                         MainMirrorStateEnum stateFilter) throws InternalException, UserException {
        List<Object> params = new ArrayList<Object>();
        String filter1 = SqlUtil.getTimeFilterPart(creationDateFilter, FIELD_CREATED_AT);
        String filter2 = SqlUtil.getTimeFilterPart(modifyingDateFilter, FIELD_MODIFIED_AT);
        String filter3 = " ";
        if (hostNameFilter != null) {
            filter3 = " AND h.name LIKE ? ";
            params.add("%" + hostNameFilter + "%");
        }
        String filter4 = requestStateFilter == null ? " " :
                " AND " + FIELD_STATE + " = " + requestStateFilter.getValue();
        String filter5 = stateFilter == null ? " " :
                " AND " + FIELD_IS_WWW + " = " + stateFilter.getValue();
        String countString = String.format(SELECT_REQUESTS_HISTORY_COUNT_QUERY,
                filter1,
                filter2,
                filter3,
                filter4,
                filter5);
        String queryString = String.format(SELECT_REQUESTS_HISTORY_QUERY,
                filter1,
                filter2,
                filter3,
                filter4,
                filter5,
                "%1$s");
        return getJdbcTemplate(WMCPartition.nullPartition()).pageableSelect(countString, queryString, mapper, pager,
                params.toArray());
    }


    @Required
    public void setUserInfoService(UserInfoService userInfoService) {
        this.userInfoService = userInfoService;
    }
}
