package ru.yandex.webmaster3.worker.download.turbo;

import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import ru.yandex.webmaster3.core.turbo.model.autoparser.AutoparserToggleState;
import ru.yandex.webmaster3.core.turbo.model.feed.TurboFeedType;
import ru.yandex.webmaster3.core.util.IdUtils;
import ru.yandex.webmaster3.core.util.UrlUtils;
import ru.yandex.webmaster3.core.util.functional.ThrowingConsumer;
import ru.yandex.webmaster3.storage.download.common.MdsExportTaskData;
import ru.yandex.webmaster3.storage.download.common.TurboSearchUrlSamplesMdsExportDescriptor;
import ru.yandex.webmaster3.storage.turbo.dao.statistics.TurboSearchUrlSamplesCHDao;
import ru.yandex.webmaster3.storage.turbo.service.autoparser.TurboAutoparserInfoService;
import ru.yandex.webmaster3.worker.download.AbstractMdsDataProvider;

import static ru.yandex.webmaster3.core.util.functional.ThrowingConsumer.rethrowingUnchecked;

@Slf4j
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class TurboSearchUrlSamplesMdsDataProvider extends AbstractMdsDataProvider<TurboSearchUrlSampleCsvRow> {

    private static final Pattern SOURCES_PATTERN = Pattern.compile(",");
    private static final long CHUNK_SIZE = 100000;

    private final TurboSearchUrlSamplesCHDao turboSearchUrlSamplesCHDao;
    private final TurboAutoparserInfoService turboAutoparserInfoService;

    @Override
    public void provide(MdsExportTaskData exportTaskData, ThrowingConsumer<TurboSearchUrlSampleCsvRow, Exception> consumer) throws Exception {
        var exportDescriptor = (TurboSearchUrlSamplesMdsExportDescriptor)exportTaskData.getDescriptor();
        String domain = exportDescriptor.getDomain();
        long samplesCount = turboSearchUrlSamplesCHDao.getSamplesCount(domain, exportDescriptor.getTurboType()).orElse(0L);

        if (samplesCount == 0L) {
            rethrowingUnchecked(consumer).accept(new TurboSearchUrlSampleCsvRow(null, null, null, null, 0));
            return;
        }

        boolean autoparserEnabled = turboAutoparserInfoService.getAutoparseCheckBoxState(domain) == AutoparserToggleState.ON;

        for (long offset = 0; offset < samplesCount; offset += CHUNK_SIZE) {
            var samples = turboSearchUrlSamplesCHDao.getSamples(domain, offset, CHUNK_SIZE, exportDescriptor.getTurboType());
            samples.stream()
                    .map(sample -> {
                        try {
                            String unicodeDomain = IdUtils.IDN.toUnicode(sample.getDomain());
                            String url = UrlUtils.urlToUnicode(sample.getUrl());
                            return new TurboSearchUrlSampleCsvRow(
                                    unicodeDomain,
                                    url,
                                    sample.getFeed(),
                                    toUserReadableSource(sample.getSource(), autoparserEnabled),
                                    sample.getIsSearchable());
                        } catch (Exception e) {
                            // Плохой сэмпл, пропускаем чтобы не фэйлить выгрузку
                            log.error("Skipping bad sample: {}", sample, e);
                            return null;
                        }
                    })
                    .filter(Objects::nonNull)
                    .filter(r -> r.getSource() != null)
                    .forEach(r -> rethrowingUnchecked(consumer).accept(r));
        }
    }

    @Override
    public Class<TurboSearchUrlSampleCsvRow> getRowClass() {
        return TurboSearchUrlSampleCsvRow.class;
    }

    private static String toUserReadableSource(String rawSource, boolean autoparserEnabled) {
        // может быть несколько источников
        return SOURCES_PATTERN.splitAsStream(rawSource).map(TurboFeedType::byCode)
                .map(st -> sourceTypeToHumanReadableString(st, autoparserEnabled)).sorted().distinct()
                .collect(Collectors.joining(","));
    }

    private static String sourceTypeToHumanReadableString(TurboFeedType sourceType, boolean autoparserEnabled) {
        switch (sourceType) {
            case RSS:
                return "rss";
            case YML:
                return "yml";
            case AUTO:
            case AUTO_DISABLED:
                return autoparserEnabled ? "autoparser" : "autoparser_off";
            case AUTO_MORDA:
                return "auto_main";
            case YML_LISTING:
                return "yml_listing";
            case API:
                return "api";
            default:
                throw new IllegalStateException("Unsupported source " + sourceType);
        }
    }

}
