package ru.yandex.webmaster3.core.turbo;

import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

import io.micrometer.core.instrument.util.IOUtils;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
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.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.http.WebmasterErrorResponse;
import ru.yandex.webmaster3.core.metrics.externals.AbstractExternalAPIService;
import ru.yandex.webmaster3.core.metrics.externals.ExternalDependencyMethod;
import ru.yandex.webmaster3.core.security.tvm.TVMTokenService;
import ru.yandex.webmaster3.core.turbo.model.ban.TurboToolsBanRequest;
import ru.yandex.webmaster3.core.util.JavaMethodWitness;
import ru.yandex.webmaster3.core.util.json.JsonMapping;
import ru.yandex.wmtools.common.sita.UserAgentEnum;


@RequiredArgsConstructor(onConstructor_ = {@Autowired})
@Slf4j
public class TurboToolsBanUrlService extends AbstractExternalAPIService {
    @Value("https://turbo-tools.yandex.net/bans/tvmapi/ban")
    private URI turboToolsServiceBanUrl;
    @Setter
    private TVMTokenService tvmTokenService;

    private CloseableHttpClient httpClient;

    public void init() {
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(1)
                .setConnectTimeout(100)
                .setSocketTimeout(60_000)
                .setRedirectsEnabled(false)
                .build();

        httpClient = HttpClients.custom()
                .setUserAgent(UserAgentEnum.WEBMASTER.getValue())
                .setMaxConnPerRoute(150)
                .setMaxConnTotal(150)
                .setConnectionTimeToLive(4, TimeUnit.SECONDS)
                .setDefaultRequestConfig(requestConfig)
                .disableCookieManagement()
                .build();
    }

    @NotNull
    private HttpPost createBanRequest(String domain, String url) {
        HttpPost httpReq = new HttpPost(turboToolsServiceBanUrl);
        log.info("json req: [host: {}, turbo_url: {}]", domain, url);
        httpReq.setEntity(new StringEntity(JsonMapping.writeValueAsString(new TurboToolsBanRequest(domain, url)),
                ContentType.APPLICATION_JSON));
        httpReq.addHeader(TVMTokenService.TVM2_TICKET_HEADER, tvmTokenService.getToken());
        return httpReq;
    }

    @ExternalDependencyMethod("turbo-url-ban")
    public TurboUrlBanServiceResponse banUrl(String domain, String url) {
        return trackQuery(new JavaMethodWitness() {
        }, ALL_ERRORS_INTERNAL, () -> {
            var httpRequest = createBanRequest(domain, url);
            log.info("Request: {}", httpRequest.getRequestLine());
            try (CloseableHttpResponse httpResponse = httpClient.execute(httpRequest)) {
                int code = httpResponse.getStatusLine().getStatusCode();
                if (code != HttpStatus.SC_OK) {
                    log.error("banUrl [domain={}, url={}, status={}, body={}]", domain, url, code,
                            IOUtils.toString(httpResponse.getEntity().getContent(),
                                    StandardCharsets.UTF_8));
                    throw new WebmasterException("TurboTools error: ",
                            new WebmasterErrorResponse.TurboErrorResponse(getClass(),
                                    null,
                                    "TurboTools return error code " + code));
                } else {
                    return JsonMapping.OM.readValue(httpResponse.getEntity().getContent(),
                            TurboUrlBanServiceResponse.class);
                }
            } catch (IOException e) {
                log.error(e.getMessage());
                throw new WebmasterException("TurboTools IO error: ",
                        new WebmasterErrorResponse.UnableToInstantateRequestResponse(getClass()));
            }
        });
    }
}
