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

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import lombok.RequiredArgsConstructor;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Triple;
import org.joda.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.feeds.feed.NativeFeedInfo2;
import ru.yandex.webmaster3.core.feeds.feed.NativeFeedSccStatus;
import ru.yandex.webmaster3.core.feeds.feed.NativeFeedStatus;
import ru.yandex.webmaster3.core.feeds.feed.NativeFeedType;
import ru.yandex.webmaster3.core.http.ActionResponse;
import ru.yandex.webmaster3.core.http.ReadAction;
import ru.yandex.webmaster3.core.metrics.Category;
import ru.yandex.webmaster3.core.util.IdUtils;
import ru.yandex.webmaster3.core.util.WwwUtil;
import ru.yandex.webmaster3.core.util.json.JsonMapping;
import ru.yandex.webmaster3.storage.abt.AbtService;
import ru.yandex.webmaster3.storage.abt.model.Experiment;
import ru.yandex.webmaster3.storage.cache.DashboardCacheService;
import ru.yandex.webmaster3.storage.cache.DashboardType;
import ru.yandex.webmaster3.storage.feeds.FeedsNative2YDao;
import ru.yandex.webmaster3.storage.feeds.logs.FeedsOffersLogsHistoryCHDao;
import ru.yandex.webmaster3.storage.feeds.logs.GoodsOffersLogsHistoryCHDao;
import ru.yandex.webmaster3.viewer.http.AbstractUserVerifiedHostAction;
import ru.yandex.webmaster3.viewer.http.AbstractUserVerifiedHostRequest;

/**
 * Created by kravchenko99 on 11.07.22
 */
@Slf4j
@ReadAction
@Category("feeds")
@Component("/dashboard/feeds/info")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class GetFeedsInfoDashboardAction extends AbstractUserVerifiedHostAction<GetFeedsInfoDashboardAction.Req,
        GetFeedsInfoDashboardAction.GetFeedsInfoDashboardResponse> {
    public static final String SER_VER = "v8";
    private static final DashboardType DASHBOARD_TYPE = DashboardType.FEEDS;
    private final DashboardCacheService dashboardCacheService;
    private final FeedsNative2YDao feedsNative2YDao;
    private final GoodsOffersLogsHistoryCHDao goodsOffersLogsHistoryCHDao;
    private final FeedsOffersLogsHistoryCHDao feedsOffersLogsHistoryCHDao;
    private final AbtService abtService;

    @Override
    public GetFeedsInfoDashboardResponse process(Req request) {
        WebmasterHostId hostId = request.getHostId();
        String domain = WwwUtil.cutWWWAndM(hostId);
        var domainHostId = IdUtils.urlToHostId(domain);

        boolean inExp = abtService.isInHashExperiment(request.getUserId(), Experiment.FEEDS_DASHBOADR_CACHE);
        if (inExp) {
            Optional<GetFeedsInfoDashboardResponse> responseOpt = dashboardCacheService.getDataUnchecked(domainHostId,
                    DASHBOARD_TYPE,
                    SER_VER,
                    (valueBytes) -> JsonMapping.readValue(valueBytes, GetFeedsInfoDashboardResponse.class));

            if (responseOpt.isPresent()) {
                return responseOpt.get();
            }
        }

        List<NativeFeedInfo2> nativeFeedInfos = feedsNative2YDao.list(domain);

        List<Triple<Long, Long, Long>> ids = nativeFeedInfos.stream()
                .filter(x -> x.getType() == NativeFeedType.STORES)
                .map(x -> Triple.of(x.getBusinessId(), x.getPartnerId(), x.getFeedId()))
                .toList();

        Set<Triple<Long, Long, Long>> feedsWithErrors = goodsOffersLogsHistoryCHDao.getLastState(ids)
                .stream()
                .filter(x -> x.getStatus().getFeedStatus() == NativeFeedStatus.FAILED)
                .map(x -> Triple.of(x.getBusinessId(), x.getPartnerId(), x.getFeedId()))
                .collect(Collectors.toSet());

        Set<String> nonGoodsFeedsWithValidationErrors = feedsOffersLogsHistoryCHDao.getLastState(
                nativeFeedInfos.stream().filter(f -> f.getType() != NativeFeedType.STORES)
                        .map(NativeFeedInfo2::getUrl).collect(Collectors.toList())
        ).stream().filter(Objects::nonNull)
                .filter(x -> x.getStats().getOk() == 0 && x.getStats().getError() > 0)
                .map(FeedsOffersLogsHistoryCHDao.FeedRecord::getUrl)
                .collect(Collectors.toSet());

        boolean hasFailedGoodsFeedsBySccTv = nativeFeedInfos.stream()
                .filter(x -> x.getType() == NativeFeedType.STORES)
                .anyMatch(x -> x.getStatusScc() == NativeFeedSccStatus.FAILED
                        || x.getStatusScc() == NativeFeedSccStatus.DISABLED_BY_PINGER);

        boolean hasFailedGoodsFeedsBySccUs = nativeFeedInfos.stream()
                .filter(x -> x.getType() != NativeFeedType.STORES)
                .anyMatch(x -> x.getStatusScc() == NativeFeedSccStatus.FAILED
                        || x.getStatusScc() == NativeFeedSccStatus.DISABLED_BY_PINGER);

        boolean hasFailedGoodsFeedsByValidationTv = nativeFeedInfos.stream()
                .filter(x -> x.getType() == NativeFeedType.STORES)
                .anyMatch(x -> feedsWithErrors.contains(Triple.of(x.getBusinessId(), x.getPartnerId(), x.getFeedId())));

        boolean hasFailedGoodsFeedsByValidationUs = nativeFeedInfos.stream()
                .filter(x -> x.getType() != NativeFeedType.STORES)
                .anyMatch(x -> nonGoodsFeedsWithValidationErrors.contains(x.getUrl()));

        FeedsDashboardStatus feedsDashboardStatus;
        FeedsDashboardStatus2 dashboardStatus;
        if ((hasFailedGoodsFeedsBySccTv || hasFailedGoodsFeedsByValidationTv) && (hasFailedGoodsFeedsBySccUs || hasFailedGoodsFeedsByValidationUs)) {
            dashboardStatus = FeedsDashboardStatus2.ERRORS_TV_AND_US;
        } else if (hasFailedGoodsFeedsBySccTv) {
            dashboardStatus = FeedsDashboardStatus2.SCC_ERRORS_GOODS;
        } else if (hasFailedGoodsFeedsByValidationTv) {
            dashboardStatus = FeedsDashboardStatus2.VALIDATION_ERRORS_GOODS;
        } else if (hasFailedGoodsFeedsBySccUs) {
            dashboardStatus = FeedsDashboardStatus2.SCC_ERRORS_US;
        } else if (hasFailedGoodsFeedsByValidationUs) {
            dashboardStatus = FeedsDashboardStatus2.VALIDATION_ERRORS_US;
        } else {
            dashboardStatus = null;
        }

        if (hasFailedGoodsFeedsBySccTv) {
            feedsDashboardStatus = FeedsDashboardStatus.SCC_ERRORS;
        } else if (hasFailedGoodsFeedsByValidationTv) {
            feedsDashboardStatus = FeedsDashboardStatus.VALIDATION_ERRORS;
        } else {
            feedsDashboardStatus = null;
        }

        var result = new GetFeedsInfoDashboardResponse(feedsDashboardStatus, dashboardStatus);
        if (inExp) {

            dashboardCacheService.saveData(domainHostId, DASHBOARD_TYPE, SER_VER, JsonMapping.writeValueAsBytes(result),
                    Duration.standardMinutes(5));
        }
        return result;
    }


    public static class Req extends AbstractUserVerifiedHostRequest {
    }

    @Value
    public static class GetFeedsInfoDashboardResponse implements ActionResponse.NormalResponse {
        FeedsDashboardStatus feedsDashboardStatus;
        FeedsDashboardStatus2 dashboardStatus;
    }

    public enum FeedsDashboardStatus {
        SCC_ERRORS,
        VALIDATION_ERRORS
    }

    public enum FeedsDashboardStatus2 {
        SCC_ERRORS_GOODS,
        VALIDATION_ERRORS_GOODS,
        SCC_ERRORS_US,
        VALIDATION_ERRORS_US,
        ERRORS_TV_AND_US,
    }
}
