package ru.yandex.webmaster3.internal.user.host;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;

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.util.IdUtils;
import ru.yandex.webmaster3.internal.common.InternalAction;
import ru.yandex.webmaster3.internal.common.security.InternalGrant;
import ru.yandex.webmaster3.core.user.UserVerifiedHost;
import ru.yandex.webmaster3.storage.user.service.UserHostsService;

/**
 * @author avhaliullin
 */
@Description("Проверить подтвержденность прав для пачки пар пользователь+хост")
@ReadAction
public class BatchHostIsVerifiedByUserAction extends InternalAction<BatchHostIsVerifiedByUserRequest, BatchHostIsVerifiedByUserResponse> {
    private static final Logger log = LoggerFactory.getLogger(BatchHostIsVerifiedByUserAction.class);

    public BatchHostIsVerifiedByUserAction() {
        super(InternalGrant.USER_HOST);
    }

    private UserHostsService userHostsService;

    @Override
    public BatchHostIsVerifiedByUserResponse process(BatchHostIsVerifiedByUserRequest request) throws WebmasterException {
        Map<String, WebmasterHostId> address2HostId = new HashMap<>();
        Map<Long, Set<WebmasterHostId>> queriesMap = new HashMap<>();
        Set<String> badHosts = new HashSet<>();
        for (UserHostQuery query : request.getUsersHosts()) {
            try {
                WebmasterHostId hostId = IdUtils.urlToHostId(query.getHostAddress());
                address2HostId.put(query.getHostAddress(), hostId);
                queriesMap.computeIfAbsent(query.getUserId(), ign -> new HashSet<>()).add(hostId);
            } catch (Exception e) {
                log.warn("Failed to parse host " + query.getHostAddress(), e);
                badHosts.add(query.getHostAddress());
            }
        }
        if (!badHosts.isEmpty()) {
            return new BatchHostIsVerifiedByUserResponse.InvalidHostAddressesResponse(badHosts);
        }

        Map<Long, Set<WebmasterHostId>> verifiedHosts = new HashMap<>();
        for (Map.Entry<Long, Set<WebmasterHostId>> entry : queriesMap.entrySet()) {
            Stream<UserVerifiedHost> verifiedStream = userHostsService.getVerifiedHosts(
                    new WebmasterUser(entry.getKey()), entry.getValue()).stream();
            if (!request.isShowInvisible()) {
                // выкинем читерные подтверждения
                verifiedStream = verifiedStream.filter(uvh -> uvh.getVerificationType().isDisplayable());
            }
            verifiedHosts.put(entry.getKey(), verifiedStream.map(UserVerifiedHost::getWebmasterHostId)
                    .collect(Collectors.toSet()));
        }
        List<UserHostResult> result = new ArrayList<>();
        for (UserHostQuery query : request.getUsersHosts()) {
            WebmasterHostId hostId = address2HostId.get(query.getHostAddress());
            boolean verified = verifiedHosts.get(query.getUserId()).contains(hostId);
            result.add(new UserHostResult(query.getUserId(), query.getHostAddress(), verified));
        }
        return new BatchHostIsVerifiedByUserResponse.NormalResponse(result);
    }

    @Required
    public void setUserHostsService(UserHostsService userHostsService) {
        this.userHostsService = userHostsService;
    }
}
