package org.micord.service;

import org.micord.config.DatabaseConnection;
import org.micord.config.S3HttpConnection;
import org.micord.models.RequestArgument;
import org.micord.models.S3Request;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.net.HttpURLConnection;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * @author Maksim Tereshin
 */
@Service
public class S3Service {

	private static final Logger logger = LoggerFactory.getLogger(S3Service.class);

	@Autowired
	private SqlAqlService sqlAndAqlService;

	@Autowired
	private HttpClient httpClient;

	public void processS3Requests(List<S3Request> s3Requests, List<String> ids) {
		if (s3Requests != null) {
			s3Requests.forEach(request -> {
				List<CompletableFuture<Void>> futures = ids.stream()
					.map(id -> CompletableFuture.runAsync(() -> processS3Request(request, id)))
					.toList();

				CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
					.thenRun(() -> logger.info("Successfully processed all S3 requests."))
					.exceptionally(ex -> {
						logger.error("Failed to process S3 requests", ex);
						return null;
					});
			});
		}
	}

	private void processS3Request(S3Request request, String id) {
		try {
			List<String> files = new ArrayList<>();

			if (request.getRequestArguments() != null && !request.getRequestArguments().isEmpty()) {
				for (RequestArgument argument : request.getRequestArguments()) {
					try (Connection connection = DatabaseConnection.getConnection(argument.getSqlConnectionParams())) {
						String query = argument.getRequestURL();
						List<String> result = sqlAndAqlService.fetchFileListFromDatabaseSQL(connection, query);
						if (result != null && !result.isEmpty()) {
							files.addAll(result);
						}
					} catch (SQLException e) {
						logger.error("Failed to execute query for RequestArgument", e);
					}
				}
			}

			files.forEach(file -> {
				HttpRequest httpRequest;
				try {
					httpRequest = S3HttpConnection.buildHttpRequest(request, file);
				} catch (Exception e) {
					throw new RuntimeException(e);
				}

				httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString())
					.thenAccept(response -> {
						if (response.statusCode() == HttpURLConnection.HTTP_NO_CONTENT || response.statusCode() == HttpURLConnection.HTTP_OK) {
							logger.info("Successfully deleted object for ID {}", id);
						} else {
							logger.error("Failed to delete object for ID {}. Response code: {}", id, response.statusCode());
						}
					})
					.exceptionally(ex -> {
						logger.error("Failed to delete object for ID {}", id, ex);
						return null;
					});
			});

		} catch (Exception e) {
			logger.error("Failed to process S3 request for id: {}", id, e);
		}
	}

}
