package ru.yandex.webmaster3.core.zora;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.ProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.cookie.Cookie;
import org.apache.http.cookie.CookieOrigin;
import org.apache.http.cookie.CookieSpec;
import org.apache.http.cookie.SM;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.impl.cookie.DefaultCookieSpec;
import org.apache.http.protocol.HttpContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.yandex.webmaster3.core.data.WebmasterHostId;

/**
 * Created by Oleg Bazdyrev on 05/10/2017.
 * Хитрый редирект для Зоры, заменяющий https на соотв. заголовок
 */
public class ZoraRedirectStrategy extends DefaultRedirectStrategy {

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

    private final boolean saveCookies;
    private CookieSpec cookieSpec = new DefaultCookieSpec();

    public ZoraRedirectStrategy(boolean saveCookies) {
        this.saveCookies = saveCookies;
    }

    @Override
    public HttpUriRequest getRedirect(
            final HttpRequest request,
            final HttpResponse response,
            final HttpContext context) throws ProtocolException {

        URI uri = getLocationURI(request, response, context);
        // location здесь уже не может быть null
        boolean locationIsAbsolute = createLocationURI(response.getFirstHeader("location").getValue()).isAbsolute();
        boolean isHttps = false;
        if (uri.getScheme().equalsIgnoreCase(WebmasterHostId.Schema.HTTPS.getSchemaName())) {
            isHttps = true;
            try {
                uri = new URIBuilder(uri).setScheme(WebmasterHostId.Schema.HTTP.getSchemaName()).build();
            } catch (URISyntaxException e) {
                throw new RuntimeException(e);
            }
        }

        final String method = request.getRequestLine().getMethod();
        RequestBuilder requestBuilder;
        if (method.equalsIgnoreCase(HttpHead.METHOD_NAME)) {
            requestBuilder = RequestBuilder.create(HttpHead.METHOD_NAME);
        } else if (method.equalsIgnoreCase(HttpGet.METHOD_NAME)) {
            requestBuilder = RequestBuilder.create(HttpGet.METHOD_NAME);
        } else {
            final int status = response.getStatusLine().getStatusCode();
            if (status == HttpStatus.SC_TEMPORARY_REDIRECT) {
                requestBuilder = RequestBuilder.copy(request);
            } else {
                requestBuilder = RequestBuilder.create(HttpGet.METHOD_NAME);
            }
        }
        requestBuilder.setUri(uri);
        // копируем заголовки
        for (Header header : request.getAllHeaders()) {
            requestBuilder.addHeader(header);
        }
        // если Location абсолютный, то выставим заголовок X-Yandex-Use-Https в зависимости от протокола
        if (locationIsAbsolute) {
            requestBuilder.removeHeaders(ZoraForValidatorsService.USE_HTTPS_HEADER_NAME);
            if (isHttps) {
                requestBuilder.addHeader(ZoraForValidatorsService.USE_HTTPS_HEADER_NAME, "1");
            }
        }
        // Cookie support
        if (saveCookies) {
            final HttpClientContext clientContext = HttpClientContext.adapt(context);
            final CookieOrigin cookieOrigin = clientContext.getCookieOrigin();
            if (cookieOrigin != null) {
                List<Cookie> cookies = new ArrayList<>();
                for (Header cookieHeader : response.getHeaders(SM.SET_COOKIE)) {
                    cookies.addAll(cookieSpec.parse(cookieHeader, cookieOrigin));
                }
                log.info("Cookies list: {}", cookies);
                // добавляем все кукисы в реквест
                if (!cookies.isEmpty()) {
                    cookieSpec.formatCookies(cookies).forEach(requestBuilder::addHeader);
                }
            }
        }

        return requestBuilder.build();
    }

}
