package ru.yandex.webmaster3.storage.robotstxt;

import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.jetbrains.annotations.NotNull;
import org.joda.time.DateTime;
import org.joda.time.Instant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.data.WebmasterUser;
import ru.yandex.webmaster3.storage.events.data.WMCEventContent;
import ru.yandex.webmaster3.storage.events.data.events.UserHostMessageEvent;
import ru.yandex.webmaster3.storage.events.service.WMCEventsService;
import ru.yandex.webmaster3.storage.user.UserTakeoutDataProvider;
import ru.yandex.webmaster3.storage.user.message.content.MessageContent;
import ru.yandex.webmaster3.storage.user.notification.NotificationType;


/**
 * WMC-6417
 *
 * @author akhazhoyan 11/2018
 */
@Service("robotsTxtService")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class RobotsTxtService implements UserTakeoutDataProvider {
    private static final Logger log = LoggerFactory.getLogger(RobotsTxtService.class);

    private final RobotsTxtHistoryYDao robotsTxtHistoryYDao;
    private final RobotsTxtSentNotificationsYDao robotsTxtSentNotificationsYDao;
    private final WMCEventsService wmcEventsService;

    public List<Long> getRobotsTxtTimestampsMillis(WebmasterHostId hostId) {
        return robotsTxtHistoryYDao.getRobotsTxtUpdates(hostId)
                .stream()
                .map(Instant::getMillis)
                .sorted(Comparator.reverseOrder())
                .limit(100L)
                .collect(Collectors.toList());
    }

    public String getRobotsTxtContent(
            WebmasterHostId hostId,
            long timestampMillis) {
        Instant dateAdded = timestampMillisToInstant(timestampMillis);
        return robotsTxtHistoryYDao.getRobotsTxtContent(hostId, dateAdded);
    }

    public void addRobotsTxt(Collection<RobotTxtInfo> robotTxtInfos) {
        robotsTxtHistoryYDao.batchInsert(robotTxtInfos);
    }

    private static final Instant LOWER_BOUND = Instant.parse("2000-01-01");
    private static final Instant UPPER_BOUND = Instant.parse("3000-01-01");

    public static Instant timestampMillisToInstant(long timestampMillis) {
        Instant instant = new Instant(timestampMillis);
        Preconditions.checkArgument(
                instant.isAfter(LOWER_BOUND) && instant.isBefore(UPPER_BOUND),
                "Timestamp is probably not in millis: " + timestampMillis
        );
        return instant;
    }

    public void sendRobotsTxtNotification(Collection<Pair<WebmasterHostId, Long>> data, String tableId) {
        DateTime date = DateTime.parse(tableId);
        Set<Pair<WebmasterHostId, Long>> sentNotificationsByTableId = robotsTxtSentNotificationsYDao.getSentNotificationByTableId(date);

        List<Triple<WebmasterHostId, Long, DateTime>> hostsWithUserForSending =
                data.stream()
                        .filter(x -> !sentNotificationsByTableId.contains(x))
                        .map(p -> Triple.of(p.getKey(), p.getValue(), date))
                        .collect(Collectors.toList());
        List<List<Triple<WebmasterHostId, Long, DateTime>>> splitedItems = Lists.partition(hostsWithUserForSending, 2000);

        for (var items: splitedItems) {
            List<WMCEventContent> events = items.stream()
                    .map(p -> new UserHostMessageEvent<>(
                            p.getLeft(),
                            p.getMiddle(),
                            new MessageContent.RobotsTxtChange(p.getLeft(), date),
                            NotificationType.ROBOTS_TXT_CHANGE,
                            false
                    )).collect(Collectors.toList());

            wmcEventsService.addEventContents(events);
            robotsTxtSentNotificationsYDao.batchInsert(items);
        }
    }

    @Override
    public void deleteUserData(WebmasterUser user) {
        robotsTxtSentNotificationsYDao.deleteForUser(user.getUserId());
    }

    @Override
    public @NotNull List<String> getTakeoutTables() {
        return List.of(
                robotsTxtSentNotificationsYDao.getTablePath()
        );
    }
}
