package org.micord.config;

import org.micord.models.S3ConnectionParams;
import org.micord.models.S3Request;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.http.HttpRequest;
import java.nio.charset.StandardCharsets;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;

/**
 * @author Maksim Tereshin
 */
public class S3HttpConnection {

	public static HttpRequest buildHttpRequest(S3Request request, String file) throws Exception {
		S3ConnectionParams connectionParams = request.getS3ConnectionParams();
		String host = connectionParams.getHost() + ":" + connectionParams.getPort();
		String s3Key = connectionParams.getS3Key();
		String s3Secret = connectionParams.getS3Secret();
		String method = connectionParams.getMethod().toUpperCase();
		String body = connectionParams.getBody();

		String resource = "/" + file;
		String contentType = connectionParams.getContentType();
		String date = ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME);

		String signature = generateSignature(method, contentType, date, resource, s3Secret);

		HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
			.uri(URI.create("https://" + host + resource))
			.header("Host", host)
			.header("Date", date)
			.header("Content-Type", contentType)
			.header("Authorization", "AWS " + s3Key + ":" + signature);


		switch (method) {
			case "DELETE":
				requestBuilder.DELETE();
				break;
			case "GET":
				requestBuilder.GET();
				break;
			case "PUT":
				requestBuilder.PUT(HttpRequest.BodyPublishers.ofString(body != null ? body : ""));
				break;
			case "POST":
				requestBuilder.POST(HttpRequest.BodyPublishers.ofString(body != null ? body : ""));
				break;
			default:
				throw new IllegalArgumentException("Unsupported HTTP method: " + method);
		}

		return requestBuilder.build();
	}

	private static String generateSignature(String method, String contentType, String date, String resource, String s3Secret) throws Exception {
		String stringToSign = method + "\n" +
			"\n" + // MD5 - not used for DELETE requests
			contentType + "\n" +
			date + "\n" +
			resource;

		Mac mac = Mac.getInstance("HmacSHA1");
		SecretKeySpec secretKey = new SecretKeySpec(s3Secret.getBytes(StandardCharsets.UTF_8), "HmacSHA1");
		mac.init(secretKey);

		byte[] hash = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
		return Base64.getEncoder().encodeToString(hash);
	}

}
