package ru.yandex.webmaster3.core.addurl;

import NCrawl.Feeds;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.joda.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.http.HttpConstants;
import ru.yandex.webmaster3.core.http.WebmasterErrorResponse;
import ru.yandex.webmaster3.core.logbroker.writer.LogbrokerClient;
import ru.yandex.webmaster3.core.metrics.externals.AbstractExternalAPIService;
import ru.yandex.webmaster3.core.metrics.externals.ExternalDependencyMethod;
import ru.yandex.webmaster3.core.util.JavaMethodWitness;
import ru.yandex.webmaster3.core.util.RetryUtils;
import ru.yandex.webmaster3.core.util.URLEncodeUtil;
import ru.yandex.webmaster3.core.util.UrlUtils;

import java.io.IOException;
import java.net.URI;
import java.util.concurrent.TimeUnit;

/**
 * @author tsyplyaev
 */
@Service("addUrlService")
@Slf4j
public class AddUrlService extends AbstractExternalAPIService {
    private static final RetryUtils.RetryPolicy LB_WRITE_RETRY_POLICY = RetryUtils.linearBackoff(5, Duration.standardSeconds(30));

    private static final String RECRAWL_FEED_NAME = "webmaster-addurl";
    private static final String DELETE_FEED_NAME = "webmaster-fast-ban-ext";
    private static final String PARAMETER_URL = "?url=";
    private static final int SOCKET_TIMEOUT_MS = 2000;

    private final URI recrawlServiceUrl;
    private final CloseableHttpClient httpClient;

    private final LogbrokerClient samovarFeedsExtLogbrokerClient;

    @Autowired
    public AddUrlService(
            @Value("${webmaster3.core.recrawlService.url}") URI recrawlServiceUrl,
            LogbrokerClient samovarFeedsExtLogbrokerClient) {
        this.recrawlServiceUrl = recrawlServiceUrl;
        this.samovarFeedsExtLogbrokerClient = samovarFeedsExtLogbrokerClient;

        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(SOCKET_TIMEOUT_MS)
                .setConnectTimeout(HttpConstants.DEFAULT_CONNECT_TIMEOUT)
                .build();

        httpClient = HttpClients.custom()
                .setDefaultRequestConfig(requestConfig)
                .setConnectionTimeToLive(30, TimeUnit.SECONDS)
                .build();
    }

    public void destroy() {
        IOUtils.closeQuietly(httpClient);
    }

    @ExternalDependencyMethod("recrawl")
    public void requestDelete(String fullUrl) throws RecrawlServiceException {
        trackExecution(new JavaMethodWitness() {}, ALL_ERRORS_INTERNAL, () -> {
            String requestUri = recrawlServiceUrl + PARAMETER_URL + URLEncodeUtil.urlEncode(fullUrl);
            HttpGet httpRequest = new HttpGet(requestUri);
            try (CloseableHttpResponse httpResponse = httpClient.execute(httpRequest)) {
                int code = httpResponse.getStatusLine().getStatusCode();
                if (code == HttpStatus.SC_BAD_REQUEST) {
                    // BadRequest бесполезно пересылать повторно
                    throw new RecrawlServiceException("Unable to recrawl url: BadRequest 400", false);
                }
                if (code != HttpStatus.SC_ACCEPTED && code != HttpStatus.SC_OK) {
                    throw new RecrawlServiceException("Unable to recrawl url: " + fullUrl + " status=" + code);
                }
            } catch (IOException e) {
                throw new RecrawlServiceException("Unable to recrawl url: " + fullUrl, e);
            }
        });
    }

    public void requestDeleteSamovar(String fullUrl) {
        String canonizedUrl = UrlUtils.canonizeUrlForRobot(fullUrl);
        if (canonizedUrl == null) {
            log.error("Failed to canonize url: {}", fullUrl);
            canonizedUrl = fullUrl;
        }

        log.info("DeletingChangeHostRegionsAction {} to Samovar", fullUrl);
        byte[] data = Feeds.TFeedExt.newBuilder()
                .setFeedName(DELETE_FEED_NAME)
                .setUrl(canonizedUrl)
                .build()
                .toByteArray();

        try {
            RetryUtils.execute(LB_WRITE_RETRY_POLICY, () -> samovarFeedsExtLogbrokerClient.write(data));
        } catch (Exception e) {
            throw new WebmasterException("Unable to send request to Logbroker",
                    new WebmasterErrorResponse.LogbrokerErrorResponse(this.getClass(), e));
        }
    }

    public void requestRecrawl(String fullUrl) {
        String canonizedUrl = UrlUtils.canonizeUrlForRobot(fullUrl);
        if (canonizedUrl == null) {
            log.error("Failed to canonize url: {}", fullUrl);
            canonizedUrl = fullUrl;
        }

        log.info("Sending {} to Samovar", fullUrl);
        byte[] data = Feeds.TFeedExt.newBuilder()
                .setFeedName(RECRAWL_FEED_NAME)
                .setUrl(canonizedUrl)
                .build()
                .toByteArray();

        try {
            RetryUtils.execute(LB_WRITE_RETRY_POLICY, () -> samovarFeedsExtLogbrokerClient.write(data));
        } catch (Exception e) {
            throw new WebmasterException("Unable to send request to Logbroker",
                    new WebmasterErrorResponse.LogbrokerErrorResponse(this.getClass(), e));
        }
    }
}
