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.beans.factory.annotation.Required;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;

import ru.yandex.common.framework.user.UserInfo;
import ru.yandex.wmconsole.data.DelegationNotificationInfo;
import ru.yandex.wmconsole.data.partition.WMCPartition;
import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.error.InternalProblem;
import ru.yandex.wmtools.common.service.AbstractDbService;
import ru.yandex.wmtools.common.service.UserService;

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

    private static final String FIELD_HOST_ID = "host_id";
    private static final String FIELD_USER_ID_GOT = "user_id_got";
    private static final String FIELD_USER_ID_GAVE = "user_id_gave";
    private static final String FIELD_MAY_REDELEGATE = "may_redelegate";
    private static final String FIELD_GIVING_DELEGATION = "giving_delegation";
    private static final String FIELD_DATE = "date";
    private static final String FIELD_KEY = "issue_id";


    private static final String SELECT_DELEGATION_NOTIFICATION_INFO_QUERY =
            " SELECT " +
                    FIELD_HOST_ID + ", " +
                    FIELD_USER_ID_GOT + ", " +
                    FIELD_USER_ID_GAVE + ", " +
                    FIELD_MAY_REDELEGATE + ", " +
                    FIELD_GIVING_DELEGATION + ", " +
                    FIELD_DATE + " " +
                    " FROM tbl_notification_delegation " +
                    " WHERE " +
                    FIELD_KEY + " = ? ";

    private static final String INSERT_DELEGATION_NOTIFICATION_QUERY =
            " INSERT INTO " +
                    " tbl_notification_delegation (" +
                    FIELD_HOST_ID + ", " +
                    FIELD_USER_ID_GOT + ", " +
                    FIELD_USER_ID_GAVE + ", " +
                    FIELD_MAY_REDELEGATE + ", " +
                    FIELD_GIVING_DELEGATION + ", " +
                    FIELD_DATE +
                    ") VALUES (?, ?, ?, ?, ?, ?)";

    private UserService userService;
    private HostInfoService hostInfoService;

    public DelegationNotificationInfo getDelegationNotificationInfo(long id) throws InternalException {
        DelegationNotificationInfo info = getJdbcTemplate(WMCPartition.nullPartition()).queryForObject(
                SELECT_DELEGATION_NOTIFICATION_INFO_QUERY, DELEGATION_INFO_MAPPER, id);

        if (info == null) {
            throw new InternalException(InternalProblem.INTERNAL_PROBLEM, "Failed to get notification " + id + ". Cause: HostInfoService failed");
        }

        UserInfo userGaveInfo = userService.getUserInfo(info.getUserIdGave());
        info.setUserGaveInfo(userGaveInfo);
        if (userGaveInfo == null) {
            throw new InternalException(InternalProblem.NO_SUCH_USER_IN_PASSPORT, "Can't notify about delegation: user " + info.getUserIdGave() + " not found in passport");
        }

        String hostName = hostInfoService.getHostNameByHostId(info.getHostId());
        info.setHostName(hostName);

        return info;
    }

    public long insertDelegationNotification(final DelegationNotificationInfo info) throws InternalException {
        GeneratedKeyHolder generatedKeyHolder = new GeneratedKeyHolder();
        PreparedStatementCreator psc = new PreparedStatementCreator() {
            @Override
            public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
                PreparedStatement ps = connection.prepareStatement(INSERT_DELEGATION_NOTIFICATION_QUERY,
                        Statement.RETURN_GENERATED_KEYS);

                log.debug("Inserting delegation notification: ");

                ps.setLong(1, info.getHostId());
                ps.setLong(2, info.getUserIdGot());
                ps.setLong(3, info.getUserIdGave());
                ps.setByte(4, info.isMayRedelegate() ? (byte) 1 : (byte) 0);
                ps.setByte(5, info.isGivingDelegation() ? (byte) 1 : (byte) 0);
                ps.setTimestamp(6, new Timestamp(info.getDelegationDate().getTime()));
                return ps;
            }
        };

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

    private final ParameterizedRowMapper<DelegationNotificationInfo> DELEGATION_INFO_MAPPER = new ParameterizedRowMapper<DelegationNotificationInfo>() {
        @Override
        public DelegationNotificationInfo mapRow(ResultSet rs, int i) throws SQLException {
            long hostId = rs.getLong(FIELD_HOST_ID);
            long userIdGot = rs.getLong(FIELD_USER_ID_GOT);
            long userIdGave = rs.getLong(FIELD_USER_ID_GAVE);
            boolean mayRedelegate = rs.getByte(FIELD_MAY_REDELEGATE) == 1;
            boolean givingDelegation = rs.getByte(FIELD_GIVING_DELEGATION) == 1;
            Date date = rs.getTimestamp(FIELD_DATE);
            return new DelegationNotificationInfo(hostId, userIdGot, userIdGave, mayRedelegate, givingDelegation, date, null, null);
        }
    };

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

    @Required
    public void setHostInfoService(HostInfoService hostInfoService) {
        this.hostInfoService = hostInfoService;
    }
}
