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

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

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

import ru.yandex.webmaster3.core.data.L10nEnum;
import ru.yandex.webmaster3.core.data.W3RegionInfo;
import ru.yandex.webmaster3.core.metrics.Category;
import ru.yandex.webmaster3.core.regions.W3RegionsTreeService;
import ru.yandex.webmaster3.core.worker.task.TaskResult;
import ru.yandex.webmaster3.storage.download.DownloadInfo;
import ru.yandex.webmaster3.storage.download.DownloadInfoYDao;
import ru.yandex.webmaster3.storage.download.DownloadStatus;
import ru.yandex.webmaster3.storage.recommendedquery.RecommendedQueriesService;
import ru.yandex.webmaster3.storage.recommendedquery.download.DownloadRecommendedQueriesTaskData;
import ru.yandex.webmaster3.storage.recommendedquery.download.RecommendedQueryCsvRow;
import ru.yandex.webmaster3.storage.recommendedquery.samples.RecommendedQuery;
import ru.yandex.webmaster3.worker.ProcessingCountLimitedTask;
import ru.yandex.webmaster3.worker.download.DownloadRunnerService;

/**
 * Created by ifilippov5 on 20.03.17.
 */
@Slf4j
@Category("recommended")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class DownloadRecommendedQueriesTask extends ProcessingCountLimitedTask<DownloadRecommendedQueriesTaskData> {

    private static final L10nEnum defaultRegionNameLanguage = L10nEnum.RU;

    private final RecommendedQueriesService recommendedQueriesService;
    private final DownloadRunnerService downloadRunnerService;
    private final W3RegionsTreeService w3regionsTreeService;
    private final DownloadInfoYDao downloadInfoYDao;

    @Override
    public Result run(DownloadRecommendedQueriesTaskData data) {
        List<RecommendedQueryCsvRow> samples;
        try {
            samples = getSamples(data);
        } catch (Exception e) {
            log.error("Download task with hostId = {} and hash = {} terminate in status Internal Error through exception during get data",
                    data.getHostId(), data.getHash(), e);
            downloadInfoYDao.add(data.getHostId(), data.getHash(), DownloadInfo.error());
            throw e;
        }
        downloadRunnerService.run(data, samples);
        return new Result(TaskResult.SUCCESS);
    }

    private List<RecommendedQueryCsvRow> getSamples(DownloadRecommendedQueriesTaskData data) {
        long queriesCount = recommendedQueriesService.getQueriesCount(data.getHostId(), data.getFilters(), data.getInclude());
        if (queriesCount == 0) {
            return Collections.emptyList();
        }
        List<RecommendedQuery> samples = recommendedQueriesService.getQueries(data.getHostId(),
                data.getFilters(), data.getOrderBy(), data.getOrderDirection(), 0, queriesCount, data.getInclude());

        L10nEnum lang = data.getLang() == null ? defaultRegionNameLanguage : data.getLang();
        return samples.stream()
                .filter(s -> s.getRegionId() != 10_000L) //TODO: workaround for WMC-4343
                .map(
                        urlSample -> new RecommendedQueryCsvRow(
                                urlSample.toRoundedSample(),
                                data.getExportFormat().getDoubleFormatter(),
                                getRegionName(urlSample.getRegionId(), lang)
                        )
                ).collect(Collectors.toList());
    }

    private String getRegionName(long regionId, L10nEnum language) {
        W3RegionInfo regionInfo = w3regionsTreeService.getExactRegionInfo((int) regionId);
        String regionName = getRegionNameByLanguage(regionInfo, language);
        if (regionName == null) {
            log.warn("Info about region with regionId = " + regionId + " is unavailable. Try to find info about parent region.");
            W3RegionInfo parentRegionInfo = w3regionsTreeService.getVisibleParent((int) regionId, Objects::nonNull);
            while (parentRegionInfo != null) {
                log.debug("Parent region id: {}", parentRegionInfo.getId());
                String parentRegionName = getRegionNameByLanguage(parentRegionInfo, language);
                if (parentRegionName != null) {
                    return parentRegionName;
                }
                parentRegionInfo = w3regionsTreeService.getVisibleParent(parentRegionInfo.getId(), Objects::nonNull);
            }
            throw new RuntimeException("Info about region with regionId = " + regionId + " and parent regions is unavailable");
        }
        return regionName;
    }

    private String getRegionNameByLanguage(W3RegionInfo regionInfo, L10nEnum language) {
        if (regionInfo == null) {
            return null;
        }
        if (regionInfo.getNames() == null) {
            return regionInfo.getDefaultName();
        }
        String regionName = regionInfo.getNames().get(language);
        if (regionName == null) {
            // Если для требуемого языка ничего не нашлось, пробуем найти название на любом другом языке
            Optional<String> regionNameOpt = regionInfo.getNames().values().stream().filter(Objects::nonNull).findAny();
            return regionNameOpt.orElse(null);
        } else {
            return regionName;
        }
    }

    @Override
    public Class<DownloadRecommendedQueriesTaskData> getDataClass() {
        return DownloadRecommendedQueriesTaskData.class;
    }
}
