package ru.yandex.wmconsole.service;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

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.VerificationNotificationInfo;
import ru.yandex.wmconsole.data.partition.WMCPartition;
import ru.yandex.wmconsole.verification.VerificationTypeEnum;
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 VerificationNotificationService extends AbstractDbService implements GroupableByHostService<VerificationNotificationInfo> {
    private static final Logger log = LoggerFactory.getLogger(VerificationNotificationService.class);

    private UserService userService;
    private HostInfoService hostInfoService;

    public Long insertVerificationNotification(final VerificationNotificationInfo info) throws InternalException {

        final String INSERT_VERIFICATION_NOTIFICATION_QUERY =
                "INSERT INTO tbl_notification_verification " +
                        " (verification_type, user_id, host_id, date) " +
                        " VALUES(?, ?, ?, ?) ";

        GeneratedKeyHolder generatedKeyHolder = new GeneratedKeyHolder();
        PreparedStatementCreator psc = new PreparedStatementCreator() {
            @Override
            public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
                PreparedStatement ps = connection.prepareStatement(INSERT_VERIFICATION_NOTIFICATION_QUERY,
                        Statement.RETURN_GENERATED_KEYS);

                log.debug("Inserting verification notification: ");
                log.debug("Verification type:" + info.getType().name());
                log.debug("User id: " + info.getUserId());
                log.debug("Host id: " + info.getHostId());
                log.debug("Date: " + info.getVerificationDate());

                ps.setInt(1, info.getType().value());
                ps.setLong(2, info.getUserId());
                ps.setLong(3, info.getHostId());
                ps.setLong(4, info.getVerificationDate().getTime());
                return ps;
            }
        };

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

    public VerificationNotificationInfo getNotificationInfo(long notificationId) throws InternalException {

        final String SELECT_VERIFICATION_NOTIFICATION_QUERY =
                " SELECT verification_type, user_id, host_id, date " +
                        " FROM tbl_notification_verification " +
                        " where issue_id = ? ";

        VerificationNotificationInfo info = getJdbcTemplate(WMCPartition.nullPartition()).queryForObject(
                SELECT_VERIFICATION_NOTIFICATION_QUERY,
                VERIFICATION_NOTIFICATION_MAPPER,
                notificationId);

        if (info == null) {
            throw new InternalException(InternalProblem.INTERNAL_PROBLEM,
                    "Failed to get notification " + notificationId + " from tbl_notification_verification");
        }

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

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

        return info;
    }

    private final ParameterizedRowMapper<VerificationNotificationInfo> VERIFICATION_NOTIFICATION_MAPPER = new ParameterizedRowMapper<VerificationNotificationInfo>() {
        @Override
        public VerificationNotificationInfo mapRow(ResultSet resultSet, int i) throws SQLException {
            long userId = resultSet.getLong("user_id");
            long hostId = resultSet.getLong("host_id");
            return new VerificationNotificationInfo(
                    new Date(resultSet.getLong("date")),
                    hostId,
                    userId,
                    null,
                    null,
                    VerificationTypeEnum.R.fromValueOrNull(resultSet.getInt("verification_type")));
        }
    };

    @Override
    public VerificationNotificationInfo getSingleNotification(Long id) throws InternalException {
        return getNotificationInfo(id);
    }

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

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