package ru.yandex.wmconsole.notifier.handler;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;

import ru.yandex.wmconsole.data.NotificationTypeEnum;
import ru.yandex.wmconsole.data.VerificationNotificationInfo;
import ru.yandex.wmconsole.service.NotificationService;
import ru.yandex.wmconsole.service.UsersHostsService;
import ru.yandex.wmconsole.service.VerificationNotificationService;
import ru.yandex.wmconsole.verification.VerificationTypeEnum;
import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.error.UserException;
import ru.yandex.wmtools.common.service.UserService;

/**
 * @author avhaliullin
 */
public class VerificationNotificationHandler implements Handler {
    private static final Logger log = LoggerFactory.getLogger(VerificationNotificationHandler.class);

    private VerificationNotificationService verificationNotificationService;
    private NotificationService notificationService;
    private UsersHostsService usersHostsService;

    @Override
    public void handleNotification(String xmlData) {
        throw new UnsupportedOperationException("handleNotification not supported for Verification notification");
    }

    @Override
    public void internalHandle(String... params) {
        throw new UnsupportedOperationException("deprecated method. Use handleInternalNotification instead");
    }
    @Override
    public void handleInternalNotification(Map<String, String> params) {
        final Long hostId;
        final Long userId;
        final VerificationTypeEnum type;
        Date verDate;
        try {
            hostId = MapParamUtil.getRequiredLongParam(params, "host_id");
            userId = MapParamUtil.getRequiredLongParam(params, "user_id");
            log.debug("Handling verification notification.");
            int verificationType = MapParamUtil.getRequiredIntParam(params, "ver_type");
            type = VerificationTypeEnum.R.fromValueOrNull(verificationType);
            if (type == null) {
                String error = "Invalid ver_type value: " + verificationType;
                log.error(error);
                return;
            }
            try {
                verDate = new Date(MapParamUtil.getLongParam(params, "ver_date"));
            } catch (Throwable t) {
                verDate = new Date();
            }
            log.debug("Params: " + hostId + ", " + userId + ", " + type + ", " + verDate);
        } catch (UserException e) {
            String error = "Internal notify: Required param missed.";
            log.error(error, e);
            return;
        }

        List<Long> users;
        if (!VerificationTypeEnum.CHEAT.equals(type)) {
            try {
                users = getUsersToNotify(hostId, userId);
            } catch (InternalException e) {
                log.error("Failed to get users for host " + hostId + " . Cause: " + e.getMessage());
                return;
            }
        } else {
            users = new ArrayList<Long>();
        }

        VerificationNotificationInfo info = new VerificationNotificationInfo(verDate, hostId, userId, type);

        long issueId;
        try {
            issueId = verificationNotificationService.insertVerificationNotification(info);
        } catch (InternalException e) {
            log.error("Failed to insert verification notification additional info. Cause: " + e.getMessage());
            return;
        }

        try {
            if (!users.isEmpty()) {
                notificationService.insertNotificationForUsers(NotificationTypeEnum.HOST_VERIFIED, issueId, users, info.getVerificationDate());
            }
            notificationService.insertNotificationForUser(NotificationTypeEnum.HOST_VERIFIED_FOR_ME, issueId, userId, info.getVerificationDate());
        } catch (InternalException e) {
            log.error("Failed to insert verification notification for host " + hostId + ". Cause: " + e.getMessage());
        }
    }

    public List<Long> getUsersToNotify(long host_id, long user_id) throws InternalException {
        List<Long> users = usersHostsService.getHostVerifiedUserIds(host_id);
        users.remove(user_id);
        return users;
    }

    @Required
    public void setUsersHostsService(UsersHostsService usersHostsService) {
        this.usersHostsService = usersHostsService;
    }

    @Required
    public void setVerificationNotificationService(VerificationNotificationService verificationNotificationService) {
        this.verificationNotificationService = verificationNotificationService;
    }

    @Required
    public void setNotificationService(NotificationService notificationService) {
        this.notificationService = notificationService;
    }
}
