package org.gluu.oxauth.service.push.sns;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.inject.Inject;

import org.gluu.oxauth.model.configuration.AppConfiguration;
import org.gluu.oxauth.service.common.EncryptionService;
import org.gluu.oxauth.util.ServerUtil;
import org.gluu.persist.PersistenceEntryManager;
import org.gluu.oxauth.model.common.User;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.sns.AmazonSNS;
import com.amazonaws.services.sns.AmazonSNSClientBuilder;
import com.amazonaws.services.sns.model.CreatePlatformEndpointRequest;
import com.amazonaws.services.sns.model.CreatePlatformEndpointResult;
import com.amazonaws.services.sns.model.MessageAttributeValue;
import com.amazonaws.services.sns.model.PublishRequest;
import com.amazonaws.services.sns.model.PublishResult;

import javax.enterprise.context.ApplicationScoped;

/**
 * Provides operations to send AWS SNS push messages
 *
 * @author Yuriy Movchan Date: 08/31/2017
 */
@ApplicationScoped
public class PushSnsService {

	@Inject
    private EncryptionService encryptionService;

	@Inject
	private AppConfiguration appConfiguration;

	@Inject
    private PersistenceEntryManager ldapEntryManager;

	public AmazonSNS createSnsClient(String accessKey, String secretKey, String region) {
		String decryptedAccessKey = encryptionService.decrypt(accessKey, true);
		String decryptedSecretKey = encryptionService.decrypt(secretKey, true);

		BasicAWSCredentials credentials = new BasicAWSCredentials(decryptedAccessKey, decryptedSecretKey);
	    AmazonSNS snsClient = AmazonSNSClientBuilder.standard().withRegion(Regions.fromName(region)).withCredentials(new AWSStaticCredentialsProvider(credentials)).build();
	    
	    return snsClient;
	}

	public String createPlatformArn(AmazonSNS snsClient, String platformApplicationArn, String token, User user) {
		CreatePlatformEndpointRequest platformEndpointRequest = new CreatePlatformEndpointRequest();
		platformEndpointRequest.setPlatformApplicationArn(platformApplicationArn);
		platformEndpointRequest.setToken(token);
		
		String customUserData = getCustomUserData(user);
		platformEndpointRequest.setCustomUserData(customUserData);
		
		CreatePlatformEndpointResult platformEndpointResult = snsClient.createPlatformEndpoint(platformEndpointRequest);

		return platformEndpointResult.getEndpointArn();
	}

	public String getCustomUserData(User user) {
		String customUserData = String.format("Issuer: %s, user: %s, date: %s", appConfiguration.getIssuer(), user.getUserId(),
				ldapEntryManager.encodeTime(user.getDn(), new Date()));
		return customUserData;
	}

	public PublishResult sendPushMessage(AmazonSNS snsClient, PushPlatform platform, String targetArn, Map<String, Object> customAppMessageMap, Map<String, MessageAttributeValue> messageAttributes) throws IOException {
		Map<String, Object> appMessageMap = new HashMap<String, Object>();

		if (platform == PushPlatform.GCM) {
			appMessageMap.put("collapse_key", "single");
			appMessageMap.put("delay_while_idle", true);
			appMessageMap.put("time_to_live", 30);
			appMessageMap.put("dry_run", false);
		}

		if (customAppMessageMap != null) {
			appMessageMap.putAll(customAppMessageMap);
		}

		String message = ServerUtil.asJson(appMessageMap);

		return sendPushMessage(snsClient, platform, targetArn, message, messageAttributes);
	}

	public PublishResult sendPushMessage(AmazonSNS snsClient, PushPlatform platform, String targetArn, String message,
			Map<String, MessageAttributeValue> messageAttributes) throws IOException {
		Map<String, String> messageMap = new HashMap<String, String>();
		messageMap.put(platform.name(), message);
		message = ServerUtil.asJson(messageMap);

	    PublishRequest publishRequest = new PublishRequest();
		publishRequest.setMessageStructure("json");
		
		if (messageAttributes != null) {
			publishRequest.setMessageAttributes(messageAttributes);
		}

		publishRequest.setTargetArn(targetArn);
		publishRequest.setMessage(message);

		PublishResult publishResult = snsClient.publish(publishRequest);

		return publishResult;
	}
}
