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

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;

import ru.yandex.autodoc.common.doc.annotation.Description;
import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.host.service.HostOwnerService;
import ru.yandex.webmaster3.core.http.RequestQueryProperty;
import ru.yandex.webmaster3.core.http.WriteAction;
import ru.yandex.webmaster3.core.metrics.Category;
import ru.yandex.webmaster3.core.util.IdUtils;
import ru.yandex.webmaster3.core.util.W3Collectors;
import ru.yandex.webmaster3.core.util.WwwUtil;
import ru.yandex.webmaster3.storage.achievements.dao.AchievementsCHDao;
import ru.yandex.webmaster3.storage.achievements.dao.AchievementsData;
import ru.yandex.webmaster3.storage.achievements.dao.HostAchievementsRivalsYDao;
import ru.yandex.webmaster3.storage.achievements.model.AchievementInfo;
import ru.yandex.webmaster3.storage.achievements.model.AchievementService;
import ru.yandex.webmaster3.storage.achievements.model.AchievementTld;
import ru.yandex.webmaster3.storage.achievements.model.AchievementType;
import ru.yandex.webmaster3.storage.feeds.FeedsService;
import ru.yandex.webmaster3.storage.iks.IksService;
import ru.yandex.webmaster3.storage.services.ServiceInfo;
import ru.yandex.webmaster3.storage.services.SiteServiceService;
import ru.yandex.webmaster3.storage.services.SiteServiceType;
import ru.yandex.webmaster3.storage.turbo.service.TurboSearchUrlsStatisticsService;
import ru.yandex.webmaster3.storage.ugc.SiteRating;
import ru.yandex.webmaster3.storage.ugc.SiteRatingService;
import ru.yandex.webmaster3.storage.util.ydb.exception.WebmasterYdbException;
import ru.yandex.webmaster3.viewer.http.AbstractUserVerifiedHostAction;
import ru.yandex.webmaster3.viewer.http.AbstractUserVerifiedHostRequest;
import ru.yandex.webmaster3.viewer.http.achievements.AddHostAchievementsRivalAction.Request;

/**
 * Created by Oleg Bazdyrev on 05/10/2018.
 */
@WriteAction
@Category("achievements")
@Description("Добавление конкурента для сравнения ачивок")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class AddHostAchievementsRivalAction extends AbstractUserVerifiedHostAction<Request,
        AddHostAchievementsRivalResponse> {

    private static final int NEW_MAX_RIVALS = 20;

    private final AchievementsCHDao mdbAchievementsCHDao;
    private final SiteServiceService siteServiceService;
    private final AchievementService achievementService;
    private final HostAchievementsRivalsYDao hostAchievementsRivalsYDao;
    private final TurboSearchUrlsStatisticsService turboSearchUrlsStatisticsService;
    private final SiteRatingService siteRatingService;
    private final IksService iksService;
    private final HostOwnerService hostOwnerService;
    private final FeedsService feedsService;

    @Override
    public AddHostAchievementsRivalResponse process(Request request) {
        try {
            String domain = WwwUtil.cutWWWAndM(request.getHostId());
            Set<String> existingRivals =
                    new HashSet<>(hostAchievementsRivalsYDao.getRivalsFiltered(request.getHostId()));
            String newRival;
            try {
                newRival = IdUtils.urlToHostIdWithUpgradedValidation(request.getRivalHost()).getPunycodeHostname();
            } catch (WebmasterException | IllegalArgumentException e) {
                return new AddHostAchievementsRivalResponse.InvalidUrlResponse();
            }
            if (existingRivals.contains(newRival)) {
                return new AddHostAchievementsRivalResponse.RivalAlreadyAddedResponse();
            }
            if (existingRivals.size() >= NEW_MAX_RIVALS) {
                return new AddHostAchievementsRivalResponse.TooManyRivalsResponse();
            }
            // добавляем
            hostAchievementsRivalsYDao.addRival(request.getHostId(), newRival);
            // сразу отдадим ачивки
            String hostOwner = hostOwnerService.getMascotHostOwner(newRival);
            AchievementsData siteAchievements =
                    mdbAchievementsCHDao.getAchievementsAndProblems(request.getTld(), hostOwner);
            if (request.getTld() == AchievementTld.RU) {
                int iks = iksService.getIksValueForOwner(hostOwner);
                siteAchievements.getInfos().add(new AchievementInfo.SqiAchievementInfo(null, null, iks));
            }
            Map<AchievementType, AchievementInfo> achMap = siteAchievements.getInfos().stream()
                    .collect(W3Collectors.toEnumMap(AchievementInfo::getType, Function.identity(),
                            AchievementType.class));
            Map<SiteServiceType, ServiceInfo> siteServiceInfo = siteServiceService.getRivalInfo(newRival,
                    request.getHostId().getPunycodeHostname().equals(newRival));
            SiteRating siteRating = siteRatingService.getRating(hostOwner);
            boolean hasSuccessfulGoodFeeds = feedsService.getDomainsWithTvInSearch(List.of(domain)).size() > 0;
            if (request.getHostId().getPunycodeHostname().equals(newRival)) {
                return new AddHostAchievementsRivalResponse.NormalResponse(
                        new RivalAchievements(
                                true,
                                newRival,
                                achMap,
                                turboSearchUrlsStatisticsService.countTurboPages(newRival),
                                siteServiceInfo,
                                siteRating,
                                hasSuccessfulGoodFeeds
                        ),
                        achievementService.getAllAchievementTypes(request.getTld())
                );
            } else {
                return new AddHostAchievementsRivalResponse.NormalResponse(
                        new RivalAchievements(
                                false,
                                newRival,
                                achMap,
                                null,
                                siteServiceInfo,
                                siteRating,
                                hasSuccessfulGoodFeeds
                        ),
                        achievementService.getAllAchievementTypes(request.getTld())
                );
            }
        } catch (WebmasterYdbException e) {
            throw e.asUnchecked("Error reading rivals from Cassandra", getClass());
        }
    }

    public static final class Request extends AbstractUserVerifiedHostRequest {
        private AchievementTld tld = AchievementTld.RU;
        private String rivalHost;

        public AchievementTld getTld() {
            return tld;
        }

        @RequestQueryProperty
        public void setTld(AchievementTld tld) {
            this.tld = tld;
        }

        public String getRivalHost() {
            return rivalHost;
        }

        @RequestQueryProperty(required = true)
        @Description("Добавляемый хост (можно передать урл, но от него все равно останется только хост)")
        public void setRivalHost(String rivalHost) {
            this.rivalHost = rivalHost;
        }
    }
}
