package vn.azteam.tpf.service;

import com.google.firebase.messaging.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import vn.azteam.tpf.Constants.Constants;
import vn.azteam.tpf.service.dto.PushNotificationRequest;
import vn.azteam.tpf.service.dto.TBNotificationDTO;

import javax.transaction.Transactional;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;

@Service
public class FCMService{

    @Value("${app.firebase-configuration-file}")
    private String firebaseConfigPath;

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

    private TBNotificationService notificationService;

    public FCMService(TBNotificationService notificationService) {
        this.notificationService = notificationService;
    }

    @Transactional
    public void sendMessageToToken(PushNotificationRequest request) throws FirebaseMessagingException {

        //Save notification to Notification table
        TBNotificationDTO tBNotificationDTO = new TBNotificationDTO();
        tBNotificationDTO.setChannel("Notification");
        tBNotificationDTO.setSendTo(request.getSendTo());
        tBNotificationDTO.setContents(request.getRequestType());
        tBNotificationDTO.setTbEntityId(request.getTbEntityId());
        tBNotificationDTO.setTbCropId(request.getTbCropId());
        Instant currentDate = Instant.now();
        tBNotificationDTO.setCreatedDate(currentDate);
        tBNotificationDTO.setSendDate(currentDate);
        tBNotificationDTO.setIsRead(0);
        tBNotificationDTO.setSubject(request.getTitle());
        tBNotificationDTO.setMessage(request.getTitleContent());
        tBNotificationDTO.setClickAction(Constants.FLUTTER_NOTIFICATION_CLICK);
        tBNotificationDTO.setType(request.getTbCropType().toString());
        notificationService.save(tBNotificationDTO);

        List<String> tokens = Arrays.asList(request.getToken().split(Constants.COMMA_DOT));

        MulticastMessage message = MulticastMessage.builder()
            .setNotification(Notification.builder()
            .setTitle(request.getTitle())
            .setBody(request.getTitleContent())
            .build())
            .putData("contents",request.getRequestType())
            .putData("tbEntityId",request.getTbEntityId().toString())
            .putData("tbCropId",request.getTbCropId().toString())
            .putData("tbCropType",request.getTbCropType().toString())
            .putData("click_action",Constants.FLUTTER_NOTIFICATION_CLICK)
            .addAllTokens(tokens)
            .setAndroidConfig(getAndroidConfig(request.getTitle()).build())
            .build();

        BatchResponse response = this.sendMulticast(message);

        if (response.getFailureCount() > 0) {
            List<SendResponse> responses = response.getResponses();
            List<String> failedTokens = new ArrayList<>();
            for (int i = 0; i < responses.size(); i++) {
                if (!responses.get(i).isSuccessful()) {
                    // The order of responses corresponds to the order of the registration tokens.
                    failedTokens.add(tokens.get(i));
                }
            }
            logger.info("Message were sent failed: " + response.getFailureCount());
            System.out.println("List of tokens that caused failures: " + failedTokens);
        }
        logger.info("Message were sent successfully: " + response.getSuccessCount());
        logger.info("Sent message to token. Device token: " + request.getToken() + ", " + response);
    }

    private AndroidConfig.Builder getAndroidConfig(String topic) {
        return AndroidConfig.builder()
            .setTtl(Duration.ofMinutes(2).toMillis()).setCollapseKey(topic)
            .setPriority(AndroidConfig.Priority.HIGH).setDirectBootOk(true);
    }

    private String sendAndGetResponse(Message message) throws InterruptedException, ExecutionException {
        return FirebaseMessaging.getInstance().sendAsync(message).get();
    }

    private BatchResponse sendMulticast(MulticastMessage message) throws FirebaseMessagingException {
        return FirebaseMessaging.getInstance().sendMulticast(message);
    }

}

