package ru.yandex.webmaster3.worker.notifications.sending;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import com.datastax.driver.core.utils.UUIDs;
import com.google.common.collect.Sets;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import ru.yandex.webmaster3.storage.util.ydb.exception.WebmasterYdbException;
import ru.yandex.webmaster3.storage.mirrors.dao.AbstractNotificationsChangesCHDao;
import ru.yandex.webmaster3.storage.notifications.NotificationChannel;
import ru.yandex.webmaster3.storage.notifications.NotificationRecListId;
import ru.yandex.webmaster3.storage.user.UserPersonalInfo;
import ru.yandex.webmaster3.storage.util.clickhouse2.ClickhouseException;
import ru.yandex.webmaster3.worker.notifications.auto.AutoNotificationsSenderService;
import ru.yandex.webmaster3.worker.notifications.auto.NotificationInfo;

@Slf4j
public class ChangeNotificationTask extends AbstractSendNotificationsTask<UUID, AbstractNotificationsChangesCHDao.AbstractMessage> {

    private static final long ZK_NODE_AGE_FOR_REMOVE = TimeUnit.DAYS.toMillis(1L);
    private final boolean enabled;

    @Autowired
    private AutoNotificationsSenderService notificationsSenderService;
    @Setter
    private AbstractNotificationsChangesCHDao notificationsChangesCHDao;

    protected ChangeNotificationTask(String workerNamePrefix, boolean enabled) {
        super(workerNamePrefix);
        this.enabled = enabled;
    }

    @Override
    protected UUID getNotificationMarkStarted(UUID notificationId, int revisionId)  {
        return notificationId;
    }

    @Override
    protected boolean canBeDeleted(UUID notificationId) {
        long timestamp = UUIDs.unixTimestamp(notificationId);
        return (System.currentTimeMillis() - timestamp) > ZK_NODE_AGE_FOR_REMOVE;
    }

    @Override
    protected void clearNotificationRecord(UUID notificationId) {
        // also drop table
        notificationsChangesCHDao.dropTable(String.valueOf(UUIDs.unixTimestamp(notificationId)));
        super.clearNotificationRecord(notificationId);
    }

    @Override
    protected List<AbstractNotificationsChangesCHDao.AbstractMessage> listTargets(NotificationRecListId listId, int fromOffset, int limit) throws ClickhouseException {
        long timestamp = UUIDs.unixTimestamp(listId.getNotificationId());
        String tableId = String.valueOf(timestamp);
        return notificationsChangesCHDao.getMessages(tableId, fromOffset, limit);
    }

    @Override
    protected boolean sendToTargetByChannel(UUID uuid, AbstractNotificationsChangesCHDao.AbstractMessage message, NotificationChannel channel) {
        log.info("About to send notification {} for host {} to user {} by {}",
                message.getNotificationType(), message.getHostId(), message.getUserId(), channel);
        if (!enabled) {
            return true;
        }

        final NotificationInfo notificationInfo = NotificationInfo.builder()
                .id(uuid)
                .email(message.getEmail())
                .hostId(message.getHostId())
                .userId(message.getUserId())
                .personalInfo(new UserPersonalInfo(message.getUserId(), message.getLogin(), message.getFio(), message.getLanguage()))
                .messageContent(message.getContent())
                .channel(channel)
                .critical(false)
                .build();
        return notificationsSenderService.sendMessage(notificationInfo);
    }

    @Override
    protected void finishNotification(UUID notificationId)  {
        // ignore
    }

    @Override
    protected UUID getRecListId(UUID uuid) {
        return uuid;
    }

    @Override
    protected String extractTargetId(AbstractNotificationsChangesCHDao.AbstractMessage target) {
        return target.key();
    }

    @Override
    protected Set<NotificationChannel> extractTargetChannels(AbstractNotificationsChangesCHDao.AbstractMessage target) {
        final Set<NotificationChannel> supportedChannels = target.getNotificationType().getSupportedChannels();
        final Set<NotificationChannel> userFilter = new HashSet<>();
        if (target.isChannelEmail()) {
            userFilter.add(NotificationChannel.EMAIL);
        }
        if (target.isChannelService()) {
            userFilter.add(NotificationChannel.SERVICE);
        }
        return Sets.intersection(supportedChannels, userFilter);
    }
}
