package ru.yandex.webmaster3.storage.feeds;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import com.google.common.base.Preconditions;
import lombok.Builder;
import lombok.Value;
import org.apache.commons.lang3.tuple.Pair;
import org.joda.time.DateTime;
import org.springframework.stereotype.Repository;

import ru.yandex.webmaster3.core.feeds.feed.FeedsErrorSeverity;
import ru.yandex.webmaster3.core.util.json.JsonMapping;
import ru.yandex.webmaster3.storage.util.ydb.AbstractYDao;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.DataMapper;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.Field;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.Fields;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.ValueDataMapper;

/**
 * Created by Oleg Bazdyrev on 20.07.2022.
 * Табличка про общее состояние домена в плане админки фидов, обновляется периодически, при изменениях могут рассылаться уведомления
 */
@Repository
public class FeedsDomainNotificationsYDao extends AbstractYDao {

    protected FeedsDomainNotificationsYDao() {
        super(PREFIX_FEEDS, "feeds_domain_notifications");
    }

    private static final ValueDataMapper<FeedsDomainNotifications> VALUE_DATA_MAPPER = ValueDataMapper.create2(
            Pair.of(F.DOMAIN, FeedsDomainNotifications::getDomain),
            Pair.of(F.LAST_UPDATE, FeedsDomainNotifications::getLastUpdate),
            Pair.of(F.DEFECT_RATE_STATUS, FeedsDomainNotifications::getDefectRateStatus),
            Pair.of(F.SCC_STATUS, FeedsDomainNotifications::getSccStatus),
            Pair.of(F.VALIDATION_STATUS, FeedsDomainNotifications::getValidationStatus),
            Pair.of(F.DEFECT_RATE_NOTIFICATIONS, FeedsDomainNotifications::getDefectRateNotifications),
            Pair.of(F.LAST_DEFECT_RATE_NOTIFICATION, FeedsDomainNotifications::getLastDefectRateNotification),
            Pair.of(F.SCC_NOTIFICATIONS, FeedsDomainNotifications::getSccNotifications),
            Pair.of(F.GOOD_SCC_NOTIFICATIONS, FeedsDomainNotifications::getGoodSccNotifications),
            Pair.of(F.LAST_SCC_NOTIFICATION, FeedsDomainNotifications::getLastSccNotification),
            Pair.of(F.VALIDATION_NOTIFICATIONS, FeedsDomainNotifications::getValidationNotifications),
            Pair.of(F.LAST_VALIDATION_NOTIFICATION, FeedsDomainNotifications::getLastValidationNotification),
            Pair.of(F.SCC_FAILED_FEEDS, FeedsDomainNotifications::getSccFailedFeeds),
            Pair.of(F.VALIDATION_FAILED_FEEDS, FeedsDomainNotifications::getValidationFailedFeeds)
    );

    public void update(Collection<FeedsDomainNotifications> data) {
        batchUpdate(VALUE_DATA_MAPPER, data).execute();
    }

    public Map<String, FeedsDomainNotifications> find(Collection<String> domains) {
        Preconditions.checkState(domains != null && domains.size() <= 1000);
        return select(MAPPER).where(F.DOMAIN.in(domains)).queryForList().stream()
                .collect(Collectors.toMap(FeedsDomainNotifications::getDomain, Function.identity()));
    }

    private static final DataMapper<FeedsDomainNotifications> MAPPER = DataMapper.create(F.DOMAIN, F.LAST_UPDATE, F.DEFECT_RATE_STATUS,
            F.SCC_STATUS, F.VALIDATION_STATUS, F.DEFECT_RATE_NOTIFICATIONS, F.LAST_DEFECT_RATE_NOTIFICATION, F.SCC_NOTIFICATIONS, F.GOOD_SCC_NOTIFICATIONS,
            F.LAST_SCC_NOTIFICATION, F.VALIDATION_NOTIFICATIONS, F.LAST_VALIDATION_NOTIFICATION, F.SCC_FAILED_FEEDS, F.VALIDATION_FAILED_FEEDS,
            FeedsDomainNotifications::new);

    private interface F {
        Field<String> DOMAIN = Fields.stringField("domain");
        Field<DateTime> LAST_UPDATE = Fields.jodaDateTimeField("last_update");
        Field<FeedsErrorSeverity> DEFECT_RATE_STATUS = Fields.stringEnumField("defect_rate_status", FeedsErrorSeverity.R).makeOptional();
        Field<FeedsErrorSeverity> SCC_STATUS = Fields.stringEnumField("ssc_status", FeedsErrorSeverity.R).makeOptional();
        Field<FeedsErrorSeverity> VALIDATION_STATUS = Fields.stringEnumField("validation_status", FeedsErrorSeverity.R).makeOptional();
        Field<Integer> DEFECT_RATE_NOTIFICATIONS = Fields.intField("defect_rate_notifications");
        Field<DateTime> LAST_DEFECT_RATE_NOTIFICATION = Fields.jodaDateTimeField("last_defect_rate_notification").makeOptional();
        Field<Integer> SCC_NOTIFICATIONS = Fields.intField("scc_notifications");
        Field<Integer> GOOD_SCC_NOTIFICATIONS = Fields.intField("good_scc_notifications");
        Field<DateTime> LAST_SCC_NOTIFICATION = Fields.jodaDateTimeField("last_scc_notification").makeOptional();
        Field<Integer> VALIDATION_NOTIFICATIONS = Fields.intField("validation_notifications");
        Field<DateTime> LAST_VALIDATION_NOTIFICATION = Fields.jodaDateTimeField("last_validation_notification").makeOptional();
        Field<List<String>> SCC_FAILED_FEEDS = Fields.jsonField2("scc_failed_feeds", JsonMapping.STRING_LIST_REFERENCE);
        Field<List<String>> VALIDATION_FAILED_FEEDS = Fields.jsonField2("validation_failed_feeds", JsonMapping.STRING_LIST_REFERENCE);
    }

    @Value
    @Builder(toBuilder = true)
    public static final class FeedsDomainNotifications {

        public static final FeedsDomainNotifications EMPTY = new FeedsDomainNotifications("", null,
                FeedsErrorSeverity.FATAL, FeedsErrorSeverity.FATAL, FeedsErrorSeverity.FATAL, 0, null, 0, 0, null, 0, null,
                Collections.emptyList(), Collections.emptyList());

        String domain;
        DateTime lastUpdate;
        FeedsErrorSeverity defectRateStatus;
        FeedsErrorSeverity sccStatus;
        FeedsErrorSeverity validationStatus;
        int defectRateNotifications;
        DateTime lastDefectRateNotification;
        int sccNotifications;
        int goodSccNotifications;
        DateTime lastSccNotification;
        int validationNotifications;
        DateTime lastValidationNotification;
        List<String> sccFailedFeeds;
        List<String> validationFailedFeeds;

    }

}
