// Copyright 2016 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package io.v.todos.persistence.syncbase;

import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.util.Log;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.concurrent.Callable;

import io.v.impl.google.services.syncbase.SyncbaseServer;
import io.v.todos.model.ListSpec;
import io.v.todos.model.Task;
import io.v.todos.model.TaskSpec;
import io.v.todos.persistence.TodoListListener;
import io.v.todos.persistence.TodoListPersistence;
import io.v.todos.sharing.ShareListMenuFragment;
import io.v.v23.InputChannel;
import io.v.v23.InputChannelCallback;
import io.v.v23.InputChannels;
import io.v.v23.VFutures;
import io.v.v23.security.BlessingPattern;
import io.v.v23.security.access.AccessList;
import io.v.v23.security.access.Constants;
import io.v.v23.security.access.Permissions;
import io.v.v23.services.syncbase.BatchOptions;
import io.v.v23.services.syncbase.Id;
import io.v.v23.services.syncbase.KeyValue;
import io.v.v23.services.syncbase.SyncgroupSpec;
import io.v.v23.syncbase.Batch;
import io.v.v23.syncbase.BatchDatabase;
import io.v.v23.syncbase.ChangeType;
import io.v.v23.syncbase.Collection;
import io.v.v23.syncbase.RowRange;
import io.v.v23.syncbase.Syncgroup;
import io.v.v23.syncbase.WatchChange;
import io.v.v23.syncbase.util.Util;
import io.v.v23.verror.NoExistException;
import io.v.v23.verror.VException;

public class SyncbaseTodoList extends SyncbasePersistence implements TodoListPersistence {
    public static final String
            TAG = "SyncbaseTodoList",
            LIST_METADATA_ROW_NAME = "list",
            TASKS_PREFIX = "tasks_";

    private static final String
            SHOW_DONE_ROW_NAME = "ShowDone";

    private final Collection mList;
    private final TodoListListener mListener;
    private final IdGenerator mIdGenerator = new IdGenerator(IdAlphabets.ROW_NAME, true);
    private final Set<String> mTaskIds = new HashSet<>();
    private final Timer mMemberTimer;
    private ShareListMenuFragment mShareListMenuFragment;

    @Override
    protected void addFeatureFragments(FragmentManager manager, FragmentTransaction transaction) {
        super.addFeatureFragments(manager, transaction);
        if (transaction == null) {
            mShareListMenuFragment = ShareListMenuFragment.find(manager);
        } else {
            mShareListMenuFragment = new ShareListMenuFragment();
            transaction.add(mShareListMenuFragment, ShareListMenuFragment.FRAGMENT_TAG);
        }
        mShareListMenuFragment.persistence = this;
        mShareListMenuFragment.setEmail(getPersonalEmail());
        // TODO(alexfandrianto): I shouldn't show the sharing menu item when this person cannot
        // share the todo list with other people. (Cannot re-share in this app.)
    }

    /**
     * This assumes that the collection for this list already exists.
     */
    public SyncbaseTodoList(Activity activity, Bundle savedInstanceState, String listIdStr,
                            TodoListListener listener)
            throws VException, SyncbaseServer.StartException {
        super(activity, savedInstanceState);
        mListener = listener;

        Log.w(TAG, "syncbase todo list: " + listIdStr);
        Id listId = convertStringToId(listIdStr);
        Log.w(TAG, "after: " + listId.toString());

        // Only show the share menu if you are the owner of this list.
        if (!listId.getBlessing().equals(getPersonalBlessingsString())) {
            mShareListMenuFragment.hideShareMenuItem();
        }

        mList = getDatabase().getCollection(listId);
        InputChannel<WatchChange> listWatch = getDatabase().watch(getVContext(),
                ImmutableList.of(Util.rowPrefixPattern(mList.id(), "")));
        ListenableFuture<Void> listWatchFuture = InputChannels.withCallback(listWatch,
                new InputChannelCallback<WatchChange>() {
                    @Override
                    public ListenableFuture<Void> onNext(WatchChange change) {
                        processWatchChange(change);
                        return null;
                    }
                });
        Futures.addCallback(listWatchFuture, new SyncTrappingCallback<Void>() {
            @Override
            public void onFailure(@NonNull Throwable t) {
                if (t instanceof NoExistException) {
                    // The collection has been deleted.
                    mListener.onDelete();
                } else {
                    super.onFailure(t);
                }
            }
        });

        mMemberTimer = watchSharedTo(mList.id(), new Function<List<BlessingPattern>, Void>() {
            @Override
            public Void apply(List<BlessingPattern> patterns) {
                // Analyze these patterns to construct the emails, and fire the listener!
                List<String> emails = parseEmailsFromPatterns(patterns);
                mShareListMenuFragment.setSharedTo(emails);
                return null;
            }
        });

        // Watch the "showDone" boolean in the userdata collection and forward changes to the
        // listener.
        InputChannel<WatchChange> showDoneWatch = getDatabase()
                .watch(getVContext(), ImmutableList.of(
                        Util.rowPrefixPattern(getUserCollection().id(), SHOW_DONE_ROW_NAME)));
        trap(InputChannels.withCallback(showDoneWatch, new InputChannelCallback<WatchChange>() {
            @Override
            public ListenableFuture<Void> onNext(WatchChange result) {
                mListener.onUpdateShowDone((boolean) result.getValue());
                return null;
            }
        }));
    }

    protected List<String> parseEmailsFromPatterns(List<BlessingPattern> patterns) {
        List<String> emails = new ArrayList<>();

        for (BlessingPattern pattern : patterns) {
            if (pattern.isMatchedBy(CLOUD_BLESSING)) {
                // Skip. It's the cloud, and that doesn't count.
                continue;
            }
            if (pattern.toString().endsWith(getPersonalEmail())) {
                // Skip. It's you, and that doesn't count.
                continue;
            }
            emails.add(getEmailFromPattern(pattern));
        }
        return emails;
    }

    @Override
    public void close() {
        mMemberTimer.cancel();
        super.close();
    }

    private void processWatchChange(WatchChange change) {
        String rowName = change.getRowName();

        if (rowName.equals(SyncbaseTodoList.LIST_METADATA_ROW_NAME)) {
            ListSpec listSpec = SyncbasePersistence.castFromSyncbase(change.getValue(),
                    ListSpec.class);
            mListener.onUpdate(listSpec);
        } else if (change.getChangeType() == ChangeType.DELETE_CHANGE) {
            mTaskIds.remove(rowName);
            mListener.onItemDelete(rowName);
        } else {
            mIdGenerator.registerId(change.getRowName().substring(TASKS_PREFIX.length()));

            TaskSpec taskSpec = SyncbasePersistence.castFromSyncbase(change.getValue(),
                    TaskSpec.class);
            Task task = new Task(rowName, taskSpec);

            if (mTaskIds.add(rowName)) {
                mListener.onItemAdd(task);
            } else {
                mListener.onItemUpdate(task);
            }
        }
    }

    @Override
    public void updateTodoList(ListSpec listSpec) {
        trap(mList.put(getVContext(), LIST_METADATA_ROW_NAME, listSpec));
    }

    @Override
    public void deleteTodoList() {
        trap(getUserCollection().delete(getVContext(), mList.id().getName()));
        trap(mList.destroy(getVContext()));
    }

    private Syncgroup getListSyncgroup() {
        return getDatabase().getSyncgroup(new Id(mList.id().getBlessing(),
                computeListSyncgroupName(mList.id().getName())));
    }

    public void shareTodoList(final Iterable<String> emails) {
        // Get the syncgroup
        final Syncgroup sgHandle = getListSyncgroup();

        // Get the Syncgroup Spec and add read access. Then get the collection permissions and add
        // both read and write access. Along the way, trigger the listener's onShareChanged.

        trap(sExecutor.submit(new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                Map<String, SyncgroupSpec> specMap = VFutures.sync(sgHandle.getSpec(getVContext()));

                String version = Iterables.getOnlyElement(specMap.keySet());
                SyncgroupSpec spec = specMap.get(version);

                // Modify the syncgroup spec to update the permissions.
                Permissions perms = spec.getPerms();
                addPermissions(perms, emails, Constants.READ.getValue());
                VFutures.sync(sgHandle.setSpec(getVContext(), spec, version));

                // TODO(alexfandrianto): This should be the right place to send the invite
                // explicitly to the selected emails.

                // Analyze these patterns to construct the emails, and fire the listener!
                List<String> specEmails = parseEmailsFromPatterns(
                        perms.get(Constants.READ.getValue()).getIn());
                mShareListMenuFragment.setSharedTo(specEmails);

                // Add read and write access to the collection permissions.
                perms = VFutures.sync(mList.getPermissions(getVContext()));

                addPermissions(perms, emails, Constants.READ.getValue());
                addPermissions(perms, emails, Constants.WRITE.getValue());
                VFutures.sync(mList.setPermissions(getVContext(), perms));
                return null;
            }
        }));
    }

    @Override
    public void completeTodoList() {
        trap(Batch.runInBatch(getVContext(), getDatabase(), new BatchOptions(),
                new Batch.BatchOperation() {
                    @Override
                    public ListenableFuture<Void> run(final BatchDatabase db) {
                        return sExecutor.submit(new Callable<Void>() {
                            @Override
                            public Void call() throws Exception {
                                InputChannel<KeyValue> scan = mList.scan(getVContext(),
                                        RowRange.prefix(SyncbaseTodoList.TASKS_PREFIX));

                                List<ListenableFuture<Void>> puts = new ArrayList<>();

                                for (KeyValue kv : InputChannels.asIterable(scan)) {
                                    TaskSpec taskSpec = castFromSyncbase(kv.getValue().getElem(),
                                            TaskSpec.class);
                                    if (!taskSpec.getDone()) {
                                        taskSpec.setDone(true);
                                        puts.add(mList.put(getVContext(), kv.getKey(), taskSpec));
                                    }
                                }

                                if (!puts.isEmpty()) {
                                    puts.add(updateListTimestamp());
                                }
                                VFutures.sync(Futures.allAsList(puts));
                                return null;
                            }
                        });
                    }
                }));
    }

    // TODO(alexfandrianto): We should consider moving this helper into the main Java repo.
    // https://github.com/vanadium/issues/issues/1321
    // TODO(alexfandrianto): This allows you to repeatedly add the same blessings to the permission
    // multiple times.
    private static void addPermissions(Permissions perms, Iterable<String> emails, String tag) {
        AccessList acl = perms.get(tag);
        List<BlessingPattern> patterns = acl.getIn();
        for (String email : emails) {
            patterns.add(new BlessingPattern(blessingsStringFromEmail(email)));
        }
        perms.put(tag, acl);
    }

    public ListenableFuture<Void> updateListTimestamp() {
        ListenableFuture<io.v.todos.model.ListSpec> get = mList.get(getVContext(), LIST_METADATA_ROW_NAME,
                ListSpec.class);
        return Futures.transformAsync(get, new AsyncFunction<Object, Void>() {
            @Override
            public ListenableFuture<Void> apply(Object oldValue) throws Exception {
                ListSpec listSpec = (ListSpec) oldValue;
                listSpec.setUpdatedAt(System.currentTimeMillis());
                return mList.put(getVContext(), LIST_METADATA_ROW_NAME, listSpec);
            }
        });
    }

    @Override
    public void addTask(TaskSpec task) {
        trap(mList.put(getVContext(), TASKS_PREFIX + mIdGenerator.generateTailId(), task));
        trap(updateListTimestamp());
    }

    @Override
    public void updateTask(Task task) {
        trap(mList.put(getVContext(), task.key, task.toSpec()));
        trap(updateListTimestamp());
    }

    @Override
    public void deleteTask(String key) {
        trap(mList.delete(getVContext(), key));
        trap(updateListTimestamp());
    }

    @Override
    public void setShowDone(boolean showDone) {
        trap(getUserCollection().put(getVContext(), SHOW_DONE_ROW_NAME, showDone));
    }
}
