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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import lombok.RequiredArgsConstructor;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import ru.yandex.autodoc.common.doc.annotation.Description;
import ru.yandex.common.util.collections.Pair;
import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.http.WriteAction;
import ru.yandex.webmaster3.core.metrics.Category;
import ru.yandex.webmaster3.core.sanctions.SanctionsRecheckRequested;
import ru.yandex.webmaster3.core.util.W3Collectors;
import ru.yandex.webmaster3.storage.antispam.threats.dao.HostThreatRecheckButtonStateYDao;
import ru.yandex.webmaster3.storage.antispam.threats.dao.HostThreatRecheckQueueYDao;
import ru.yandex.webmaster3.storage.antispam.threats.dao.OwnerThreatsCHDao;
import ru.yandex.webmaster3.storage.antispam.threats.data.HostThreatInfo;
import ru.yandex.webmaster3.storage.sanctions.SanctionsCHDao;
import ru.yandex.webmaster3.viewer.http.AbstractUserVerifiedHostAction;
import ru.yandex.webmaster3.viewer.http.threats.data.NonRecheckableThreat;
import ru.yandex.webmaster3.viewer.http.threats.data.RecheckableThreat;

/**
 * @author avhaliullin
 */
@WriteAction
@Description("Запросить перепроверку всех угроз, которые перепроверяемы на данный момент")
@Category("threats")
@Component("/threats/recheck")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class RecheckHostThreatsAction extends AbstractUserVerifiedHostAction<RecheckHostThreatsRequest,
        RecheckHostThreatsResponse> {
    private final HostThreatRecheckButtonStateYDao hostThreatRecheckButtonStateYDao;
    private final HostThreatRecheckQueueYDao hostThreatRecheckQueueYDao;
    private final OwnerThreatsCHDao mdbOwnerThreatsCHDao;
    private final SanctionsCHDao sanctionsCHDao;

    @Override
    public RecheckHostThreatsResponse process(RecheckHostThreatsRequest request) {
        List<RecheckableThreat> recheckable = new ArrayList<>();
        List<NonRecheckableThreat> nonRecheckable = new ArrayList<>();
        List<HostThreatInfo> threats = mdbOwnerThreatsCHDao.getHostWithThreats(request.getHostId()).getThreats();

        if (threats.isEmpty()) {
            return new RecheckHostThreatsResponse.NoThreatsToRecheckResponse();
        }

        Map<String, DateTime> threat2ButtonPress = new HashMap<>();
        Map<WebmasterHostId, List<HostThreatInfo>> sourceHost2Threats = threats
                .stream()
                .filter(HostThreatInfo::isAllowedToRecheck)
                .collect(Collectors.groupingBy(HostThreatInfo::getThreatSourceHost));

        for (Map.Entry<WebmasterHostId, List<HostThreatInfo>> entry : sourceHost2Threats.entrySet()) {
            Set<String> threatsForSource = entry.getValue()
                    .stream()
                    .map(HostThreatInfo::getThreat)
                    .collect(Collectors.toSet());
            threat2ButtonPress.putAll(
                    hostThreatRecheckButtonStateYDao.getRecordsForHost(entry.getKey(), threatsForSource)
            );
        }

        HostThreatUtil.classifyThreats(threats, threat2ButtonPress, recheckable, nonRecheckable);
        if (recheckable.isEmpty()) {
            return new RecheckHostThreatsResponse.NoThreatsToRecheckResponse();
        }

        DateTime now = DateTime.now();
        Set<String> recheckableThreats = recheckable.stream()
                .map(RecheckableThreat::getThreat)
                .collect(Collectors.toSet());
        hostThreatRecheckQueueYDao.insertHostForRecheck(request.getHostId(), now, recheckableThreats);
        Map<Pair<WebmasterHostId, String>, HostThreatInfo> threat2Info = threats
                .stream()
                .collect(Collectors.toMap(a -> Pair.of(a.getThreatSourceHost(), a.getThreat()), Function.identity(),
                        W3Collectors.replacingMerger()));
        for (RecheckableThreat threat : recheckable) {
            HostThreatInfo threatInfo = threat2Info.get(Pair.of(threat.getHostId(), threat.getThreat()));
            hostThreatRecheckButtonStateYDao.insertRecord(
                    threatInfo.getThreatSourceHost(),
                    threatInfo.getThreat(),
                    now,
                    request.getHostId(),
                    request.getUserId(),
                    threatInfo.getRecheckInterval()
            );
        }
        sanctionsCHDao.insertSanctionsIntoTempTable(SanctionsRecheckRequested.create(request.getUserId(),
                request.getHostId(), recheckableThreats));
        return new RecheckHostThreatsResponse.NormalResponse();
    }

}
