package org.mercury_im.messenger.core.store.caps;

import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smackx.caps.cache.EntityCapsPersistentCache;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.mercury_im.messenger.core.SchedulersFacade;
import org.mercury_im.messenger.core.data.repository.EntityCapsRepository;
import org.mercury_im.messenger.entity.caps.EntityCapsRecord;

import java.io.StringReader;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.inject.Inject;
import javax.inject.Singleton;

import io.reactivex.disposables.CompositeDisposable;

@Singleton
public class MercuryEntityCapsStore implements EntityCapsPersistentCache {

    private static final Logger LOGGER = Logger.getLogger(MercuryEntityCapsStore.class.getName());

    private final CompositeDisposable disposable = new CompositeDisposable();
    private final EntityCapsRepository repository;
    private final SchedulersFacade schedulers;

    @Inject
    public MercuryEntityCapsStore(EntityCapsRepository entityCapsRepository,
                                  SchedulersFacade schedulers) {
        this.repository = entityCapsRepository;
        this.schedulers = schedulers;
    }

    @Override
    public void addDiscoverInfoByNodePersistent(String nodeVer, DiscoverInfo info) {
        LOGGER.log(Level.INFO, "MercuryEntityCapsStore: addDiscoverInfoByNodePersistent: " + nodeVer);
        EntityCapsRecord record = new EntityCapsRecord();
        record.setNodeVer(nodeVer);
        record.setXml(info.toXML().toString());

        disposable.add(repository.insertEntityCapsRecord(record)
                .subscribeOn(schedulers.getIoScheduler())
                .subscribe());
    }

    @Override
    public DiscoverInfo lookup(String nodeVer) {
        LOGGER.log(Level.INFO, "MercuryEntityCapsStore: lookup: " + nodeVer);
        EntityCapsRecord defaultIfEmpty = new EntityCapsRecord();
        EntityCapsRecord record = repository.maybeGetEntityCapsRecord(nodeVer)
                .defaultIfEmpty(defaultIfEmpty)
                .subscribeOn(schedulers.getIoScheduler())
                .blockingGet();
        if (record == defaultIfEmpty) {
            return null;
        }
        try {
            return parseDiscoverInfo(record);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private DiscoverInfo parseDiscoverInfo(EntityCapsRecord record) throws Exception {
        XmlPullParser parser = PacketParserUtils.getParserFor(new StringReader(record.getXml()));
        return (DiscoverInfo) PacketParserUtils.parseIQ(parser);
    }

    @Override
    public void emptyCache() {
        LOGGER.log(Level.INFO, "MercuryEntityCapsStore: emptyCache.");
        disposable.add(repository.deleteAllEntityCapsRecords()
                .subscribeOn(schedulers.getIoScheduler())
                .subscribe());
    }
}
