package ru.yandex.wmtools.common.sita.urlextension;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.yandex.wmtools.common.sita.SitaException;
import ru.yandex.wmtools.common.sita.SitaIncompleteResponseException;
import ru.yandex.wmtools.common.sita.SitaJson;
import ru.yandex.wmtools.common.util.http.YandexHttpStatus;

import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;

/**
 * User: azakharov
 * Date: 30.04.15
 * Time: 14:30
 */
public class SitaUrlExtensionJsonResponse {
    private static final Logger log = LoggerFactory.getLogger(SitaUrlExtensionJsonResponse.class);

    private static final ObjectMapper OM = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    private static final ObjectWriter LOG_OBJECT_WRITER;

    static {
        LOG_OBJECT_WRITER = OM.disable(SerializationFeature.WRITE_NULL_MAP_VALUES).writer();
    }

    public static SitaUrlExtensitonResponse parse(Reader reader) throws IOException {
        SitaJson.TResponse response = OM.readValue(reader, SitaJson.TResponse.class);
        return parseJson(response);
    }

    private static SitaUrlExtensitonResponse parseJson(SitaJson.TResponse response) throws JsonProcessingException {
        log.debug("Sita response: {}", LOG_OBJECT_WRITER.writeValueAsString(response));
        if (response.Results == null || response.Results.length == 0) {
            log.error("TResponse.Results is empty");
            throw new SitaException("Empty Sita results");
        }

        SitaJson.TActionResult result = null;
        for (SitaJson.TActionResult actionResult : response.Results) {
            if (actionResult.Type != SitaJson.EActionType.AT_URL_EXTENSION) {
                log.warn("Found unknown action result: {}", actionResult.Type);
            } else {
                result = actionResult;
                break;
            }
        }

        SitaUrlExtensitonResponse.Status status = SitaUrlExtensitonResponse.Status.OK;
        if (response.Errors != null && response.Errors.length > 0) {
            for (SitaJson.TError error : response.Errors) {
                if (error.SitaError != null) {
                    switch (error.SitaError.Code) {
                        case TIMEOUT_EXCEEDED:
                            throw new SitaIncompleteResponseException("Timeout exceeded");
                        case INCOMPLETE_RESPONSE:
                            status = SitaUrlExtensitonResponse.Status.URL_NOT_FOUND;
                            break;
                        case REDIRECTIONS_LOOP_FOUND:
                            status = SitaUrlExtensitonResponse.Status.REDIRECT_LOOP;
                            break;
                        default:
                    }
                }
            }
        }


        if (result == null
                || result.UrlExtensionResult == null) {

            log.error("Sita url extension result not found");
            throw new SitaException("Sita url extension result not found");
        } else {

            List<UrlExtensionChain.Link> chain = new ArrayList<>();
            for (SitaJson.TUrlExtensionRedirection redirection : result.UrlExtensionResult.Redirections) {
                chain.add(
                        new UrlExtensionChain.Link(
                                redirection.Url,
                                redirection.HttpCode == null ? null : YandexHttpStatus.parseCode(redirection.HttpCode)
                        )
                );
            }
            return new SitaUrlExtensitonResponse(new UrlExtensionChain(chain), status);
        }
    }
}
