package org.limewire.ui.compose.integration;

import org.limewire.util.NativeLibraryLoader;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;

public final class MacUserNotificationBridge {
    public static final int DELIVERED = 0;
    public static final int FAILED = -1;

    public static final int STATUS_UNKNOWN = -1;
    public static final int STATUS_NOT_DETERMINED = 0;
    public static final int STATUS_DENIED = 1;
    public static final int STATUS_AUTHORIZED = 2;
    public static final int STATUS_PROVISIONAL = 3;
    public static final int STATUS_EPHEMERAL = 4;

    private static final AtomicLong IDS = new AtomicLong();
    private static final Map<String, CallbackSet> CALLBACKS = new ConcurrentHashMap<String, CallbackSet>();
    private static final boolean LOADED = NativeLibraryLoader.loadFirstAvailable(
            "DesktopNotifications",
            "lib/native/libDesktopNotifications.dylib",
            "nativelibs/osx/libDesktopNotifications.dylib",
            "build/native/osx/libDesktopNotifications.dylib"
    );

    private MacUserNotificationBridge() {
    }

    public static boolean isAvailable() {
        return LOADED;
    }

    public static void initialize() {
        if (LOADED) {
            nativeInitialize();
        }
    }

    public static int authorizationStatus() {
        if (!LOADED) {
            return STATUS_UNKNOWN;
        }
        return nativeAuthorizationStatus();
    }

    public static int requestAuthorization() {
        if (!LOADED) {
            return STATUS_UNKNOWN;
        }
        return nativeRequestAuthorization();
    }

    public static int deliver(
            String title,
            String body,
            String replyPlaceholder,
            boolean playSound,
            Runnable onOpen,
            Consumer<String> onReply
    ) {
        if (!LOADED) {
            return FAILED;
        }
        String identifier = "wireshare-" + IDS.incrementAndGet();
        CALLBACKS.put(identifier, new CallbackSet(onOpen, onReply));
        int result = nativeDeliver(identifier, title, body, replyPlaceholder, playSound, onReply != null);
        if (result != DELIVERED) {
            CALLBACKS.remove(identifier);
        }
        return result;
    }

    public static void notificationActivated(String identifier) {
        CallbackSet callbacks = CALLBACKS.remove(identifier);
        if (callbacks != null && callbacks.onOpen != null) {
            callbacks.onOpen.run();
        }
    }

    public static void notificationReplied(String identifier, String replyText) {
        CallbackSet callbacks = CALLBACKS.remove(identifier);
        if (callbacks != null && callbacks.onReply != null) {
            callbacks.onReply.accept(replyText == null ? "" : replyText);
        } else if (callbacks != null && callbacks.onOpen != null) {
            callbacks.onOpen.run();
        }
    }

    private static final class CallbackSet {
        private final Runnable onOpen;
        private final Consumer<String> onReply;

        private CallbackSet(Runnable onOpen, Consumer<String> onReply) {
            this.onOpen = onOpen;
            this.onReply = onReply;
        }
    }

    private static native void nativeInitialize();

    private static native int nativeAuthorizationStatus();

    private static native int nativeRequestAuthorization();

    private static native int nativeDeliver(
            String identifier,
            String title,
            String body,
            String replyPlaceholder,
            boolean playSound,
            boolean allowReply
    );
}
