package com.infinite.focus.server.fcm.service;

import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.google.firebase.messaging.AndroidConfig;
import com.google.firebase.messaging.AndroidNotification;
import com.google.firebase.messaging.ApnsConfig;
import com.google.firebase.messaging.Aps;
import com.google.firebase.messaging.BatchResponse;
import com.google.firebase.messaging.FirebaseMessaging;
import com.google.firebase.messaging.Message;
import com.google.firebase.messaging.Notification;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.infinite.focus.server.fcm.model.PushNotification;

@Service
public class FCMService {

	private Logger logger = LoggerFactory.getLogger(FCMService.class);

	@Async
	public void sendMessage(Map<String, String> data, PushNotification request)
			throws InterruptedException, ExecutionException {
		Message message = getPreconfiguredMessageWithData(data, request);
		Gson gson = new GsonBuilder().setPrettyPrinting().create();
		String jsonOutput = gson.toJson(message);
		String response = sendAndGetResponse(message);
		logger.info("Sent message with data. Topic: " + request.getTopic() + ", " + response + " msg " + jsonOutput);
	}

	@Async
	public void sendMessageWithoutData(PushNotification request)
			throws InterruptedException, ExecutionException {
		Message message = getPreconfiguredMessageWithoutData(request);
		String response = sendAndGetResponse(message);
		logger.info("Sent message without data. Topic: " + request.getTopic() + ", " + response);
	}

	@Async
	public void sendMessageToToken(PushNotification request) throws InterruptedException, ExecutionException {
		Message message = getPreconfiguredMessageToToken(request);
		Gson gson = new GsonBuilder().setPrettyPrinting().create();
		String jsonOutput = gson.toJson(message);
		String response = sendAndGetResponse(message);
		logger.info(
				"Sent message to token. Device token: " + request.getToken() + ", " + response + " msg " + jsonOutput);
	}

	private String sendAndGetResponse(Message message) throws InterruptedException, ExecutionException {
		return FirebaseMessaging.getInstance().sendAsync(message).get();
	}
	
	private BatchResponse sendAndGetResponse(List<Message> messages) throws InterruptedException, ExecutionException {
		return FirebaseMessaging.getInstance().sendAllAsync(messages).get();
	}

	private AndroidConfig getAndroidConfig(String topic) {
		return AndroidConfig.builder().setTtl(Duration.ofMinutes(2).toMillis()).setCollapseKey(topic)
				.setPriority(AndroidConfig.Priority.HIGH)
				//.setNotification(AndroidNotification.builder().setSound(NotificationParameter.SOUND.getValue())
				//.setColor(NotificationParameter.COLOR.getValue()).setTag(topic).build())
				.build();
	}

	private ApnsConfig getApnsConfig(String topic) {
		return ApnsConfig.builder().setAps(Aps.builder().setCategory(topic).setThreadId(topic).build()).build();
	}

	private Message getPreconfiguredMessageToToken(PushNotification request) {
		return getPreconfiguredMessageBuilder(request).setToken(request.getToken()).build();
	}

	private Message getPreconfiguredMessageWithoutData(PushNotification request) {
		return getPreconfiguredMessageBuilder(request).setTopic(request.getTopic()).build();
	}

	private Message getPreconfiguredMessageWithData(Map<String, String> data, PushNotification request) {
		System.out.println("Your Token " + request.getToken());
		return getPreconfiguredMessageBuilder(request).putAllData(data).setToken(request.getToken()).build();
	}

	private Message.Builder getPreconfiguredMessageBuilder(PushNotification request) {
		AndroidConfig androidConfig = getAndroidConfig(request.getTopic());
		Notification.Builder notification = Notification.builder().setTitle(request.getTitle()).setBody(request.getMessage());
		ApnsConfig apnsConfig = getApnsConfig(request.getTopic());
		return Message.builder().setApnsConfig(apnsConfig).setAndroidConfig(androidConfig);
				//.setNotification(notification.build());
	}
	
	@Async
	public void sendMessages(Map<String, String> data, List<PushNotification> pushNotifications) throws InterruptedException, ExecutionException {
		
		List<List<Message>> messageList = new ArrayList<>();
		List<Message> messages = new ArrayList<>();
		
		for(int i = 0; i < pushNotifications.size(); i++) {
			Message message = getPreconfiguredMessageWithData(data, pushNotifications.get(i));
			messages.add(message);
			if(messages.size() == 400) {
				messageList.add(messages);
				messages = new ArrayList<>();
			}
		}
		
		if(messageList.isEmpty()) {
			Gson gson = new GsonBuilder().setPrettyPrinting().create();
			String jsonOutput = gson.toJson(messages);
			BatchResponse response = sendAndGetResponse(messages);
			logger.info("Sent message with data. Topic: " + response.toString() + " msg " + jsonOutput);
		}else {
			for(int i = 0; i < messageList.size(); i++) {
				Gson gson = new GsonBuilder().setPrettyPrinting().create();
				String jsonOutput = gson.toJson(messageList.get(i));
				BatchResponse response = sendAndGetResponse(messageList.get(i));
				logger.info("Diveded Sent message with data. Topic: " + response.toString() + " msg " + jsonOutput);
			}
		}
	}
}
