package ru.yandex.webmaster3.worker.turbo;

import java.util.Map;

import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.w3c.dom.Document;
import org.xml.sax.SAXParseException;

import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.http.WebmasterErrorResponse;
import ru.yandex.webmaster3.core.metrics.Category;
import ru.yandex.webmaster3.core.turbo.LoadTurboErrorContentTaskData;
import ru.yandex.webmaster3.core.turbo.model.TurboHostSettings;
import ru.yandex.webmaster3.core.turbo.model.error.TurboErrorType;
import ru.yandex.webmaster3.core.turbo.model.feed.TurboFeedType;
import ru.yandex.webmaster3.core.turbo.xml.TurboXMLReader;
import ru.yandex.webmaster3.core.util.XmlUtil;
import ru.yandex.webmaster3.core.worker.task.TaskResult;
import ru.yandex.webmaster3.core.zora.ZoraForValidatorsService;
import ru.yandex.webmaster3.storage.download.DownloadStatus;
import ru.yandex.webmaster3.storage.turbo.dao.TurboDownloadTask;
import ru.yandex.webmaster3.storage.turbo.dao.TurboDownloadTasksYDao;
import ru.yandex.webmaster3.storage.turbo.service.settings.TurboSettingsService;
import ru.yandex.webmaster3.worker.Task;
import ru.yandex.wmtools.common.util.http.YandexHttpStatus;

/**
 * Created by Oleg Bazdyrev on 20/04/2018.
 */
@Category("turbo")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class LoadTurboErrorContentTask extends Task<LoadTurboErrorContentTaskData> {

    private static final Logger log = LoggerFactory.getLogger(LoadTurboErrorContentTask.class);

    private final TurboSettingsService turboSettingsService;
    private final TurboDownloadTasksYDao turboDownloadTasksYDao;
    private final ZoraForValidatorsService zoraForValidatorsService;
    private Map<TurboFeedType, Long> maxFeedSize;

    @Override
    public Result run(LoadTurboErrorContentTaskData data) throws Exception {
        // скачиваем фид и ищем в нем item
        String content = null;
        TurboErrorType error = null;
        TurboHostSettings hostSettings = turboSettingsService.getSettings(data.getHostId());
        String feedUrl = hostSettings.urlWithAuthentification(data.getFeedUrl());
        try {
            Pair<TurboErrorType, String> errorAndContent = zoraForValidatorsService.processEntityGoZora(feedUrl, httpEntity -> {
                try {
                    Document doc = TurboXMLReader.parseTurboFeed(httpEntity.getContent(),
                            0, data.getItemUrl(), maxFeedSize.get(data.getFeedType()));
                    byte[] docBytes = XmlUtil.serializeDocument(doc);
                    return Pair.of(null, new String(docBytes));

                } catch (TurboXMLReader.TurboFeedIsEmptyException e) {
                    return Pair.of(TurboErrorType.PARSER_EMPTY_XML, null);
                } catch (TurboXMLReader.NoItemsFoundException e) {
                    return Pair.of(TurboErrorType.PARSER_NO_ITEMS_DUE_TO_CHANGED_FEED, null);
                } catch (TurboXMLReader.TurboFeedIsTooBigException e) {
                    return Pair.of(TurboErrorType.PARSER_XML_TOO_BIG, null);
                } catch (SAXParseException e) {
                    return Pair.of(TurboErrorType.PARSER_XML_ERROR, null);
                } catch (Exception e) {
                    return Pair.of(TurboErrorType.INTERNAL, null);
                }
            });
            error = errorAndContent.getLeft();
            content = errorAndContent.getRight();

        } catch (WebmasterException e) {
            if (e.getError() instanceof WebmasterErrorResponse.SitaErrorResponse) {
                // http error
                log.error("Zora error when downloading feed {}", data.getFeedUrl());
                WebmasterErrorResponse.SitaErrorResponse siteResp = (WebmasterErrorResponse.SitaErrorResponse) e.getError();
                Integer httpCode = siteResp.getHttpCode();
                if (httpCode == null) {
                    error = TurboErrorType.INTERNAL;
                } else if (httpCode == YandexHttpStatus.HTTP_1003_ROBOTS_TXT_DISALLOW.getCode()) {
                    error = TurboErrorType.FETCHER_DISALLOWED_IN_ROBOTS;
                } else {
                    error = TurboErrorType.FETCHER_HTTP;
                }
            } else {
                error = TurboErrorType.INTERNAL;
            }
        } catch (Exception e) {
            log.error("Error when downloading or parsing feed", e);
            if (error == null) {
                error = TurboErrorType.INTERNAL;
            }
        }
        DownloadStatus status = error != null ? DownloadStatus.INTERNAL_ERROR : DownloadStatus.DONE;
        turboDownloadTasksYDao.insertTask(
                new TurboDownloadTask(data.getTaskId(), data.getFeedType(), status, error, content));

        return new Result(TaskResult.SUCCESS);
    }

    public void setMaxFeedSize(Map<TurboFeedType, Long> maxFeedSize) {
        this.maxFeedSize = maxFeedSize;
    }

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