package org.mercury_im.messenger.core.connection.message;

import org.jivesoftware.smack.chat2.ChatManager;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.MessageBuilder;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
import org.jivesoftware.smackx.ox.OpenPgpContact;
import org.jivesoftware.smackx.ox.OpenPgpManager;
import org.jivesoftware.smackx.ox_im.OXInstantMessagingManager;
import org.jivesoftware.smackx.sid.element.OriginIdElement;
import org.mercury_im.messenger.core.connection.MercuryConnection;
import org.mercury_im.messenger.core.connection.MercuryConnectionManager;
import org.mercury_im.messenger.core.data.repository.MessageRepository;
import org.mercury_im.messenger.core.util.AppendCompletableToSingle;
import org.mercury_im.messenger.entity.chat.Chat;
import org.mercury_im.messenger.entity.chat.DirectChat;
import org.mercury_im.messenger.entity.chat.GroupChat;
import org.mercury_im.messenger.entity.message.MessageDeliveryState;

import java.util.Collection;
import java.util.Collections;
import java.util.UUID;

import io.reactivex.Completable;
import io.reactivex.Single;

public class OxMessageConsignor extends AbstractMessageConsignor {

    public OxMessageConsignor(MercuryConnectionManager connectionManager, MessageRepository messageRepository, Chat chat) {
        this(new MessageComposer(), connectionManager, messageRepository, chat);
    }

    public OxMessageConsignor(MessageComposer composer, MercuryConnectionManager connectionManager, MessageRepository messageRepository, Chat chat) {
        super(composer, connectionManager, messageRepository, chat);
    }

    @Override
    public Single<UUID> sendTextMessage(Chat chat, String body) {
        org.mercury_im.messenger.entity.message.Message message = messageComposer.createTextMessage(chat, body);
        MessageBuilder messageBuilder = commonMessageBuilder(message);

        Completable deliverMessage = null;
        if (chat instanceof DirectChat) {
            deliverMessage = sendDirectChatMessage((DirectChat) chat, messageBuilder, body);
        } else if (chat instanceof GroupChat) {
            // deliverMessage = sendGroupChatMessage((GroupChat) chat, messageBuilder);
        } else {
            throw new AssertionError("Unknown chat type.");
        }

        Single<UUID> deliverAndStore = messageRepository.insertMessage(message)
                .map(org.mercury_im.messenger.entity.message.Message::getId)
                .compose(new AppendCompletableToSingle<>(deliverMessage))
                .flatMap(messageId -> messageRepository.updateDeliveryState(messageId, MessageDeliveryState.delivered_to_server)
                        .toSingle(() -> messageId));

        return deliverAndStore;
    }

    private Completable sendDirectChatMessage(DirectChat chat, MessageBuilder messageBuilder, String body) {
        return Completable.fromAction(() -> {
            MercuryConnection connection = connectionManager.getConnection(chat.getAccount());
            OpenPgpManager ox = OpenPgpManager.getInstanceFor(connection.getConnection());
            OXInstantMessagingManager oxim = OXInstantMessagingManager.getInstanceFor(connection.getConnection());

            OpenPgpContact contact = ox.getOpenPgpContact(chat.getJid().asEntityBareJid());
            contact.updateKeys(connection.getConnection());

            OpenPgpContact self = ox.getOpenPgpSelf();
            self.updateKeys(connection.getConnection());

            Message.Body bodyElement = new Message.Body(Stanza.getDefaultLanguage(), body);
            oxim.addOxMessage(messageBuilder, contact, Collections.singletonList(bodyElement));


            ChatManager chatManager = ChatManager.getInstanceFor(connection.getConnection());
            org.jivesoftware.smack.chat2.Chat smackChat = chatManager.chatWith(chat.getJid().asEntityBareJid());
            smackChat.send(messageBuilder.build());
        });

    }

    private MessageBuilder commonMessageBuilder(org.mercury_im.messenger.entity.message.Message message) {
        return MessageBuilder.buildMessage(message.getLegacyStanzaId())
                .ofType(org.jivesoftware.smack.packet.Message.Type.chat)
                .addExtension(new OriginIdElement(message.getOriginId()))
                .to(chat.getJid())
                .from(chat.getAccount().getJid());
    }
}
