package org.mercury_im.messenger.data.repository;

import org.junit.Test;
import org.mercury_im.messenger.data.di.DaggerInMemoryDatabaseComponent;
import org.mercury_im.messenger.data.di.InMemoryDatabaseComponent;
import org.mercury_im.messenger.entity.Account;

import java.util.NoSuchElementException;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.inject.Inject;

import io.reactivex.disposables.CompositeDisposable;
import io.requery.Persistable;
import io.requery.reactivex.ReactiveEntityStore;

public class AccountRepositoryTest {

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

    @Inject
    ReactiveEntityStore<Persistable> dataStore;

    @Inject
    XmppAccountRepository accountRepository;

    @Inject
    XmppDirectChatRepository directChatRepository;

    @Inject
    XmppPeerRepository contactRepository;

    @Inject
    XmppMessageRepository messageRepository;

    @Inject
    public AccountRepositoryTest() {
        InMemoryDatabaseComponent testComponent = DaggerInMemoryDatabaseComponent.builder()
                .build();
        testComponent.inject(this);
    }

    @Test
    public void test() throws InterruptedException {
        CompositeDisposable d = new CompositeDisposable();
        d.add(accountRepository.observeAccounts()
                .distinct(Account::getId)
                .subscribe(a -> System.out.println("Observe: " + a.getAddress())));

        Thread.sleep(100);

        Account a1 = new IAccount();
        a1.setAddress("a1@example.com");
        a1.setPassword("a1a1a1");
        a1.setEnabled(true);

        d.add(accountRepository.insertAccount(a1).subscribe());

        Thread.sleep(100);

        Account a2 = new IAccount();
        a2.setAddress("a2@example.com");
        a2.setPassword("a2a2a2");
        a2.setEnabled(false);

        d.add(accountRepository.insertAccount(a2).subscribe());

        Thread.sleep(100);

        Account a3 = new IAccount();
        a3.setAddress("a3@example.com");
        a3.setPassword("a3a3a3");
        a3.setEnabled(false);

        d.add(accountRepository.insertAccount(a3).subscribe());

        Thread.sleep(100);

        a1.setAddress("a11@example.org");

        d.add(accountRepository.updateAccount(a1).subscribe());

        Thread.sleep(100);
    }

    @Test
    public void observeDeletionTest() throws InterruptedException {
        CompositeDisposable d = new CompositeDisposable();

        UUID uuid = UUID.randomUUID();
        d.add(accountRepository.observeAccount(uuid)
                .subscribe(optAccount -> {
                    LOGGER.log(Level.INFO, "Changed");
                    if (!optAccount.isPresent()) {
                        LOGGER.log(Level.INFO, "Changed: Account " + uuid.toString() + " is not present.");
                    } else {
                        LOGGER.log(Level.INFO, "Changed: Account " + uuid.toString() + ": " + optAccount.getItem().toString());
                    }
                }));

        Account account = new IAccount(uuid);
        account.setEnabled(true);
        account.setAddress("hello@world");
        account.setPassword("wooooooh");

        d.add(accountRepository.insertAccount(account)
                .subscribe(insert -> LOGGER.log(Level.INFO, "Inserted."),
                        error -> LOGGER.log(Level.SEVERE, "Inserted", error)));

        Thread.sleep(100);

        d.add(accountRepository.deleteAccount(uuid)
                .subscribe(() -> LOGGER.log(Level.INFO, "Deleted")));

        Thread.sleep(1000);
        d.dispose();
    }

    @Test(expected = NoSuchElementException.class)
    public void updateMissingEntityFails() {
        Account missingAccount = new IAccount();
        missingAccount.setAddress("this@account.is.missing");
        missingAccount.setPassword("inTheDatabase");

        accountRepository.updateAccount(missingAccount)
                .blockingGet();
    }
}
