package ch.threema.app.actions;

import android.location.Location;

import org.slf4j.Logger;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import ch.threema.app.R;
import ch.threema.app.ThreemaApplication;
import ch.threema.app.messagereceiver.MessageReceiver;
import ch.threema.app.services.MessageService;
import ch.threema.app.utils.MessageUtil;
import static ch.threema.base.utils.LoggingKt.getThreemaLogger;
import ch.threema.storage.models.AbstractMessageModel;

public class LocationMessageSendAction extends SendAction {
    private static final Logger logger = getThreemaLogger("LocationMessageSendAction");

    protected static volatile LocationMessageSendAction instance;
    private static final Object instanceLock = new Object();

    private MessageService messageService;

    private LocationMessageSendAction() {
        // Singleton
    }

    public static LocationMessageSendAction getInstance() {
        if (instance == null) {
            synchronized (instanceLock) {
                if (instance == null) {
                    instance = new LocationMessageSendAction();
                }
            }
        }
        return instance;
    }

    public boolean sendLocationMessage(
        final MessageReceiver[] allReceivers,
        final Location location,
        final @Nullable String poiName,
        final ActionHandler actionHandler
    ) {
        if (actionHandler == null) {
            return false;
        }

        var serviceManager = getServiceManager();
        if (serviceManager != null) {
            messageService = serviceManager.getMessageService();
        }

        if (messageService == null || location == null) {
            actionHandler.onError("Nothing to send");
            return false;
        }

        if (allReceivers.length < 1) {
            actionHandler.onError("no message receiver");
            return false;
        }

        // loop all receivers (required for distribution lists)
        // add distribution list members to list of receivers
        final MessageReceiver[] resolvedReceivers = MessageUtil.addDistributionListReceivers(allReceivers);
        final int numReceivers = resolvedReceivers.length;

        sendSingleMessage(resolvedReceivers[0], location, poiName, new ActionHandler() {
            int receiverIndex = 0;

            @Override
            public void onError(String errorMessage) {
                actionHandler.onError(errorMessage);
            }

            @Override
            public void onProgress(int progress, int total) {
                actionHandler.onProgress(progress + receiverIndex, numReceivers);
            }

            @Override
            public void onCompleted() {
                if (receiverIndex < numReceivers - 1) {
                    receiverIndex++;
                    sendSingleMessage(resolvedReceivers[receiverIndex], location, poiName, this);
                } else {
                    actionHandler.onCompleted();
                }
            }
        });
        return true;
    }

    private void sendSingleMessage(
        final MessageReceiver messageReceiver,
        final @NonNull Location location,
        final @Nullable String poiName,
        final @NonNull ActionHandler actionHandler
    ) {
        if (messageReceiver == null) {
            actionHandler.onError("No receiver");
            return;
        }

        try {
            messageService.sendLocation(
                location,
                poiName,
                messageReceiver,
                new MessageService.CompletionHandler() {
                    @Override
                    public void sendComplete(AbstractMessageModel messageModel) {
                    }

                    @Override
                    public void sendQueued(AbstractMessageModel messageModel) {
                        actionHandler.onCompleted();
                    }

                    @Override
                    public void sendError(int reason) {
                        actionHandler.onError(String.format(ThreemaApplication.getAppContext().getString(R.string.an_error_occurred_more), Integer.toString(reason)));
                    }
                });
        } catch (final Exception e) {
            logger.error("Could not send location message", e);
            actionHandler.onError(e.getMessage());
        }
    }
}
