package ru.yandex.webmaster3.viewer.http.user;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import ru.yandex.autodoc.common.doc.annotation.Description;
import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.data.WebmasterUser;
import ru.yandex.webmaster3.core.http.ReadAction;
import ru.yandex.webmaster3.core.http.RequestTimeout;
import ru.yandex.webmaster3.core.metrics.Category;
import ru.yandex.webmaster3.core.user.UserVerifiedHost;
import ru.yandex.webmaster3.core.util.PageUtils;
import ru.yandex.webmaster3.storage.host.moderation.camelcase.service.DisplayNameService2;
import ru.yandex.webmaster3.storage.host.service.HostService;
import ru.yandex.webmaster3.storage.user.service.UserHostsService;
import ru.yandex.webmaster3.storage.util.HostListTreeBuilder;
import ru.yandex.webmaster3.viewer.http.AbstractUserAction;
import ru.yandex.webmaster3.viewer.util.HostnameFilter;

/**
 * @author aherman
 */
@ReadAction
@Category("user")
@Description(value = "Поиск подтвержденных хостов для выпадушки \"Мои сайты\"")
@RequestTimeout(61)
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Component("/user/host/suggest")
public class SuggestHostAction extends AbstractUserAction<SuggestHostRequest, SuggestHostResponse> {
    private final UserHostsService userHostsService;
    private final HostService hostService;
    private final HostListTreeBuilder hostListTreeBuilder;
    private final DisplayNameService2 displayNameService2;

    @Override
    public SuggestHostResponse process(SuggestHostRequest request) throws WebmasterException {
        WebmasterUser user = request.getWebmasterUser();
        PageUtils.Pager page = PageUtils.getPage(1, request.getPageSize());
        HostnameFilter hostnameFilter = HostnameFilter.create(request.getHostnameFilter());
        if (hostnameFilter == null) {
            return new SuggestHostResponse.NormalResponse(Collections.emptyList());
        }

        List<UserVerifiedHost> verifiedHosts = userHostsService.getVerifiedHosts(user);

        List<WebmasterHostId> pinnedHosts = userHostsService.getPinnedHosts(user);

        Pair<List<HostListTreeBuilder.HostTreeNode>, HostListTreeBuilder.HostCounters> treeResults =
                hostListTreeBuilder.createHostTree(verifiedHosts,
                        Collections.emptyList(), pinnedHosts);

        Set<WebmasterHostId> verifiedHostIds =
                verifiedHosts.stream().map(UserVerifiedHost::getWebmasterHostId).collect(Collectors.toSet());

        List<HostListTreeBuilder.HostTreeNode> mainMirrors = treeResults.getLeft();
        List<HostListTreeBuilder.HostTreeNode> result = filter(mainMirrors, page, hostnameFilter, verifiedHostIds);
        List<SuggestHostResponse.SuggestHostInfo> commonHostInfos = new ArrayList<>(result.size());

        for (HostListTreeBuilder.HostTreeNode node : result) {
            WebmasterHostId hostId = node.getHostId();
            String displayName = displayNameService2.getHostUrlWithDisplayName(hostId);

            commonHostInfos.add(new SuggestHostResponse.SuggestHostInfo(hostId, displayName));
        }
        return new SuggestHostResponse.NormalResponse(commonHostInfos);
    }

    private List<HostListTreeBuilder.HostTreeNode> filter(List<HostListTreeBuilder.HostTreeNode> mainMirrors,
                                                          PageUtils.Pager page, HostnameFilter hostnameFilter, Set<WebmasterHostId> verifiedHostIds) {
        List<HostListTreeBuilder.HostTreeNode> result = new ArrayList<>(page.getPageSize());
        for (HostListTreeBuilder.HostTreeNode mainMirror : mainMirrors) {
            if (result.size() >= page.getPageSize()) {
                break;
            }
            filterAndAdd(result, mainMirror, hostnameFilter, verifiedHostIds);
            for (HostListTreeBuilder.HostTreeNode child : mainMirror.getChildren()) {
                if (result.size() >= page.getPageSize()) {
                    break;
                }
                filterAndAdd(result, child, hostnameFilter, verifiedHostIds);
            }
        }
        return result;
    }

    private void filterAndAdd(List<HostListTreeBuilder.HostTreeNode> result,
                              HostListTreeBuilder.HostTreeNode node, HostnameFilter hostnameFilter, Set<WebmasterHostId> verifiedHostIds) {
        WebmasterHostId hostId = node.getHostId();
        if (hostnameFilter.accept(hostId) && verifiedHostIds.contains(hostId)) {
            result.add(node);
        }
    }
}
