package ru.yandex.webmaster3.worker.user;

import java.util.Collections;

import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.metrika.counters.MetrikaCountersUtil;
import ru.yandex.webmaster3.storage.events.data.WMCEvent;
import ru.yandex.webmaster3.storage.events.data.WMCEventContent;
import ru.yandex.webmaster3.storage.events.data.events.MetrikaCounterBindingEvent;
import ru.yandex.webmaster3.storage.events.data.events.RetranslateToUsersEvent;
import ru.yandex.webmaster3.storage.events.data.events.UserHostMessageEvent;
import ru.yandex.webmaster3.storage.events.service.WMCEventsObserver;
import ru.yandex.webmaster3.storage.events.service.WMCEventsService;
import ru.yandex.webmaster3.storage.metrika.dao.MetrikaCounterBindingStateYDao;
import ru.yandex.webmaster3.storage.spam.ISpamHostFilter;
import ru.yandex.webmaster3.storage.user.message.content.MessageContent;
import ru.yandex.webmaster3.storage.user.notification.NotificationType;
import ru.yandex.webmaster3.storage.user.service.UserHostsService;

/**
 * Created by ifilippov5 on 13.02.18.
 */
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class MetrikaEventsObserver implements WMCEventsObserver {
    private static final Logger log = LoggerFactory.getLogger(MetrikaEventsObserver.class);

    private final WMCEventsService wmcEventsService;
    private final ISpamHostFilter fastSpamHostFilter;
    private final MetrikaCounterBindingStateYDao metrikaCounterBindingStateYDao;
    private final UserHostsService userHostsService;
    private boolean enabled;

    @Override
    public boolean observe(WMCEvent event) {
        WMCEventContent content = event.getContent();
        if (!(content instanceof MetrikaCounterBindingEvent)) {
            return false;
        }

        if (!enabled) {
            log.info("Metrika messages disabled, dropping event {}", event);
            return false;
        }

        MetrikaCounterBindingEvent metrikaEvent = (MetrikaCounterBindingEvent) content;
        log.info("Metrika event {} for {}:{}", metrikaEvent.getMetrikaEvent(), metrikaEvent.getDomain(), metrikaEvent.getCounterId());

        MetrikaCountersUtil.generateHostIds(metrikaEvent.getDomain()).forEach(hostId -> {
            if (fastSpamHostFilter.checkHost(hostId)) {
                log.info("Ignoring message for spam host {}", hostId);
                return;
            }

            switch (metrikaEvent.getMetrikaEvent()) {
                case CREATE:
                    addEventBindingRequest(hostId, metrikaEvent.getInitiatorId(), metrikaEvent.getCounterId());
                    break;
                case REJECT:
                    addEventBindingRequestCancelled(hostId, metrikaEvent.getDomain(), metrikaEvent.getCounterId());
                    break;
                case DISMISS:
                    addEventBindingDeleted(hostId, metrikaEvent.getCounterId(), metrikaEvent.getInitiatorLogin(),
                            metrikaEvent.getInitiatorId());
                    break;
            }
        });

        return true;
    }

    private void addEventBindingRequest(WebmasterHostId hostId, long userId, long counterId) {
        wmcEventsService.addEvent(
                new RetranslateToUsersEvent<>(
                        new UserHostMessageEvent<>(
                                hostId,
                                null,
                                new MessageContent.HostMetrikaCounterBindingRequest(
                                        hostId,
                                        counterId
                                ),
                                NotificationType.METRIKA_COUNTERS,
                                false),
                        Collections.singletonList(userId)
                )
        );
    }

    private void addEventBindingRequestCancelled(WebmasterHostId hostId, String domain, long counterId) {
        Long userId = metrikaCounterBindingStateYDao.getWebmasterUserId(domain, counterId);
        if (userId != null) {
            if (!userHostsService.isAnyHostVerified(userId, Collections.singletonList(hostId))) {
                return;
            }
            wmcEventsService.addEvent(
                    new UserHostMessageEvent<>(
                            hostId,
                            userId,
                            new MessageContent.HostMetrikaCounterBindingRequestCancelled(
                                    hostId,
                                    counterId),
                            NotificationType.METRIKA_COUNTERS,
                            false)
            );
        }
    }

    private void addEventBindingDeleted(WebmasterHostId hostId, long counterId, String user, long userId) {
        wmcEventsService.addEvent(
                new RetranslateToUsersEvent<>(
                        new UserHostMessageEvent<>(
                                hostId,
                                null,
                                new MessageContent.HostMetrikaCounterBindingDeleted(
                                        hostId,
                                        counterId,
                                        user
                                ),
                                NotificationType.METRIKA_COUNTERS,
                                false),
                        Collections.singletonList(userId)
                )
        );
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }
}
