package ru.yandex.webmaster3.core.searchquery.history;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;

import org.joda.time.DateTime;

import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.searchquery.QueryFilter;

/**
 * @author tsyplyaev
 */
public class GroupModifications {
    private final WebmasterHostId hostId;
    private final UUID groupId;
    private final DateTime dateTime;
    private final Map<ModificationType, GroupModification> modifications;

    public GroupModifications(WebmasterHostId hostId, UUID groupId, DateTime dateTime, Map<ModificationType, GroupModification> modifications) {
        this.hostId = hostId;
        this.groupId = groupId;
        this.dateTime = dateTime;
        this.modifications = modifications;
    }

    public WebmasterHostId getHostId() {
        return hostId;
    }

    public UUID getGroupId() {
        return groupId;
    }

    public DateTime getDateTime() {
        return dateTime;
    }

    public Map<ModificationType, GroupModification> getModifications() {
        return modifications;
    }

    public static Map<ModificationType, GroupModification> extractModifications(QueryGroupState oldState, QueryGroupState newState) {
        Map<ModificationType, GroupModification> modifications = new HashMap<>();

        if (!oldState.getGroupId().equals(newState.getGroupId())) {
            throw new IllegalArgumentException("Can't calculate diff for different groups");
        }

        if (!oldState.getGroupId().isSpecial()) {
            if (!Objects.equals(oldState.getName(), newState.getName())) {
                modifications.put(ModificationType.GROUP_RENAMED, new GroupRenamed(oldState.getName(), newState.getName()));
            }

            Set<QueryFilter> oldFilters = oldState.getFilters() == null ? Collections.emptySet() : new HashSet<>(oldState.getFilters());
            Set<QueryFilter> newFilters = newState.getFilters() == null ? Collections.emptySet() : new HashSet<>(newState.getFilters());

            if (!oldFilters.equals(newFilters)) {
                modifications.put(ModificationType.GROUP_FILTER_CHANGED, new GroupFilterChanged(oldState.getFilters(), newState.getFilters()));
            }
        }

        Set<String> oldQueries = new HashSet<>(oldState.getQueries());
        Set<String> newQueries = new HashSet<>(newState.getQueries());

        Set<String> inters = new HashSet<>(oldQueries);
        inters.retainAll(newQueries);

        oldQueries.removeAll(inters);
        newQueries.removeAll(inters);

        if (!oldQueries.isEmpty()) {
            modifications.put(ModificationType.QUERIES_REMOVED, new QueriesRemoved(oldQueries));
        }

        if (!newQueries.isEmpty()) {
            modifications.put(ModificationType.QUERIES_ADDED, new QueriesAdded(newQueries));
        }

        return modifications;
    }

    public static class ModificationsContainer {
        public GroupRenamed GROUP_RENAMED;
        public GroupFilterChanged GROUP_FILTER_CHANGED;
        public QueriesAdded QUERIES_ADDED;
        public QueriesRemoved QUERIES_REMOVED;

        public Map<ModificationType, GroupModification> toMap() {
            Map<ModificationType, GroupModification> res = new HashMap<>();
            if (GROUP_RENAMED != null) {
                res.put(ModificationType.GROUP_RENAMED, GROUP_RENAMED);
            }
            if (GROUP_FILTER_CHANGED != null) {
                res.put(ModificationType.GROUP_FILTER_CHANGED, GROUP_FILTER_CHANGED);
            }
            if (QUERIES_ADDED != null) {
                res.put(ModificationType.QUERIES_ADDED, QUERIES_ADDED);
            }
            if (QUERIES_REMOVED != null) {
                res.put(ModificationType.QUERIES_REMOVED, QUERIES_REMOVED);
            }
            return res;
        }
    }
}
