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


import java.io.IOException;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import ru.yandex.autodoc.common.doc.annotation.Description;
import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.data.HttpResponsePart;
import ru.yandex.webmaster3.core.http.ReadAction;
import ru.yandex.webmaster3.core.http.WebmasterErrorResponse;
import ru.yandex.webmaster3.core.metrics.Category;
import ru.yandex.webmaster3.storage.async.AsyncRequestTaskService;
import ru.yandex.webmaster3.storage.async.model.AsyncOperationRequestInfo;
import ru.yandex.webmaster3.storage.async.model.HttpAsyncRequestInfoRequestState;
import ru.yandex.webmaster3.storage.async.model.HttpAsyncRequestInfoResultType;
import ru.yandex.webmaster3.storage.util.serverresponseutil.model.ServerResponseAnalysisErrorTransfer;
import ru.yandex.webmaster3.storage.util.serverresponseutil.model.ServerResponseAnalysisResponseType;
import ru.yandex.webmaster3.storage.util.serverresponseutil.model.ServerResponseUtilErrorType;
import ru.yandex.webmaster3.viewer.http.BaseWebmaster3Action;
import ru.yandex.webmaster3.viewer.http.async.model.AsyncInfoRequest;

/**
 * @author: ishalaru
 * DATE: 20.05.2019
 */
@ReadAction
@Description(value = "Проверка статуса заявки о скачивании страницы с сайта пользователя через Ситу")
@Category("validation")
@Slf4j
@Component("/util/serverResponse/info")
public class ServerResponseUtilInfoAction extends BaseWebmaster3Action<AsyncInfoRequest,
        ServerResponseUtilInfoResponse> {
    private static final ObjectMapper OM = new ObjectMapper();
    private static final Duration ANSWER_WAITING_TIMEOUT = Duration.standardMinutes(2);

    private final AsyncRequestTaskService asyncRequestTaskService;

    @Autowired
    public ServerResponseUtilInfoAction(AsyncRequestTaskService asyncRequestTaskService) {
        this.asyncRequestTaskService = asyncRequestTaskService;
    }

    @Override
    public ServerResponseUtilInfoResponse process(AsyncInfoRequest request) {
        AsyncOperationRequestInfo responseInfo = asyncRequestTaskService.getResponseInfo(request.getRequestId());
        if (responseInfo == null) {
            return new ServerResponseUtilInfoResponse.RequestIdNotFound(this.getClass());
        }
        if (responseInfo.getState() == HttpAsyncRequestInfoRequestState.NEW &&
                responseInfo.getLastUpdate().plus(ANSWER_WAITING_TIMEOUT).isBefore(DateTime.now())) {
            log.error("Worker failed to start request in {}", ANSWER_WAITING_TIMEOUT);
            throw new WebmasterException("TimeoutError", new WebmasterErrorResponse.AsyncZoraErrorResponse(getClass()));
//            return new ServerResponseUtilInfoResponse.RequestFailed(this.getClass());
        }
        if (responseInfo.getState() != HttpAsyncRequestInfoRequestState.TASK_FINISHED) {
            return ServerResponseUtilInfoResponse.NormalResponse.stillInProgress();
//            return new ServerResponseUtilInfoResponse.RequestStillInProgress(this.getClass());
        }
        if (responseInfo.getResult() != HttpAsyncRequestInfoResultType.OK) {
            if (responseInfo.getResult() == HttpAsyncRequestInfoResultType.INTERNAL_ERROR) {
                throw new WebmasterException("InternalError", new WebmasterErrorResponse.AsyncZoraErrorResponse(getClass()));
            } else {
                return new ServerResponseUtilInfoResponse.RequestFailed(this.getClass());
            }
        }
        if (responseInfo.getResponseObjectTypeId() == ServerResponseAnalysisResponseType.NORMAL.getValue()) {
            HttpResponsePart result = convertData(responseInfo, HttpResponsePart.class);
            if (result == null) {
                return new ServerResponseUtilInfoResponse.ResponseDataCorrupted(this.getClass());
            }
            return makeResponse(result);
        } else if (responseInfo.getResponseObjectTypeId() == ServerResponseAnalysisResponseType.HTTP_PROBLEM.getValue()) {
            ServerResponseAnalysisErrorTransfer result = convertData(responseInfo,
                    ServerResponseAnalysisErrorTransfer.class);
            return new ServerResponseUtilInfoResponse.ExtHttpStatus(this.getClass(), result.getHttpCodeInfo());

        } else {
            ServerResponseUtilErrorType serverResponseUtilErrorType = convertData(responseInfo,
                    ServerResponseUtilErrorType.class);
            return new ServerResponseUtilInfoResponse.CommonErrorResponse(this.getClass(), serverResponseUtilErrorType);

        }

    }


    public ServerResponseUtilInfoResponse makeResponse(HttpResponsePart object) {
        return new ServerResponseUtilInfoResponse.NormalResponse(object);
    }

    protected <WorkClass> WorkClass convertData(AsyncOperationRequestInfo info, Class<WorkClass> clazz) {
        WorkClass result = null;
        try {
            result = OM.readValue(info.getResponse(), clazz);
        } catch (IOException e) {
            log.error("Problem with parsing response.", e);
            return null;
        }
        return result;
    }

}
