package ervu.client.okopf;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.zip.ZipInputStream;

import ervu.exception.EsnsiException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.retry.support.RetrySynchronizationManager;
import org.springframework.stereotype.Component;

/**
 * @author Artyom Hackimullin
 */
@Component
public class EsnsiOkopfClient {
  private static final Logger LOGGER = LoggerFactory.getLogger(EsnsiOkopfClient.class);

  @Value("${esnsi.okopf.url}")
  private String url;
  @Value("${esnsi.okopf.connect.timeout:2}")
  private long connectTimeout;
  @Value("${esnsi.okopf.read.timeout:4}")
  private long readTimeout;

  @Retryable(value = {IOException.class, EsnsiException.class}, maxAttemptsExpression = "${esnsi.okopf.retry.max.attempts.load:3}", backoff =
  @Backoff(delayExpression = "${esnsi.okop.retry.delay.load:3000}"))
  public String getJsonOkopFormData() throws IOException {
    int retryCount = RetrySynchronizationManager.getContext().getRetryCount() + 1;
    LOGGER.info("Attempt #{} to load json okopf form data from URL: {}", retryCount, url);
    HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
    connection.setConnectTimeout((int) Duration.ofSeconds(connectTimeout).toMillis());
    connection.setReadTimeout((int) Duration.ofSeconds(connectTimeout).toMillis());
    int statusCode = connection.getResponseCode();
    LOGGER.info("Connecting timeout set to {} ms, read timeout set to {}", connectTimeout, readTimeout);
    if (statusCode >= 200 && statusCode <= 202) {
      try (ZipInputStream archiveStream = new ZipInputStream(connection.getInputStream());
           BufferedReader br = new BufferedReader(
               new InputStreamReader(archiveStream, StandardCharsets.UTF_8))) {
        if (Objects.nonNull(archiveStream.getNextEntry())) {
          LOGGER.info("Received an archive in response.");
          return br.lines().collect(Collectors.joining(System.lineSeparator()));
        }
        LOGGER.info("Received an empty archive in response.");
      }
    }
    throw new EsnsiException("Http status: " + statusCode +  " Skipping load okopf file process. URL: " + url);
  }

  @Recover
  public String recover(Exception e) {
    LOGGER.error("All retry attempts for IO operation failed for URL: {}. Triggering fallback logic.", url, e);
    return null;
  }
}

