/*
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.hyperaware.conference.android.ui.favsession;

import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.view.View;
import android.widget.ImageButton;

import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.hyperaware.conference.android.R;
import com.hyperaware.conference.android.logging.Logging;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * A utility class that manages the functionality of "favorites" buttons.
 *
 */

@MainThread
public class FavSessionButtonManager {

    private static final Logger LOGGER = Logging.getLogger(FavSessionButtonManager.class);

    private final FirebaseDatabase fdb;
    private final FirebaseAuth auth;
    private final AuthRequiredListener authRequiredListener;
    private final MyAuthStateListener authStateListener = new MyAuthStateListener();

    private MyUserFavoritesListener favoritesListener;
    private DatabaseReference userFavoriteSessionsRef;
    private FirebaseUser user;

    private final HashMap<String, HashSet<ImageButton>> sessionButtons = new HashMap<>();
    private final HashSet<String> favorites = new HashSet<>();

    public FavSessionButtonManager(@NonNull final FirebaseDatabase fdb, @NonNull final FirebaseAuth auth, @NonNull final AuthRequiredListener arl) {
        this.fdb = fdb;
        this.auth = auth;
        this.authRequiredListener = arl;
    }

    public void start() {
        auth.addAuthStateListener(authStateListener);
    }

    public void stop() {
        auth.removeAuthStateListener(authStateListener);
        stopListeningFavorites();
    }

    public void attach(@NonNull final ImageButton button, @NonNull final String session_id) {
        button.setOnClickListener(new MyFavSessionButtonOnClickListener(session_id));
        HashSet<ImageButton> buttons = sessionButtons.get(session_id);
        if (buttons == null) {
            buttons = new HashSet<>();
            sessionButtons.put(session_id, buttons);
        }
        buttons.add(button);
        updateButton(button, session_id);
    }

    public void detach(@NonNull final ImageButton button, @NonNull final String session_id) {
        button.setOnClickListener(null);
        final HashSet<ImageButton> buttons = sessionButtons.get(session_id);
        if (buttons != null) {
            buttons.remove(button);
        }
    }

    private void updateButton(final ImageButton button, final String session_id) {
        boolean is_fav = favorites.contains(session_id);

        final int draw_res = is_fav ?
            R.drawable.ic_favorite_black_24dp :
            R.drawable.ic_favorite_border_black_24dp;
        button.setImageResource(draw_res);

        button.setOnClickListener(new MyFavSessionButtonOnClickListener(session_id));
    }

    private void startListeningFavorites() {
        userFavoriteSessionsRef = fdb.getReference("/users/" + user.getUid() + "/favorites/sessions");
        favoritesListener = new MyUserFavoritesListener();
        userFavoriteSessionsRef.addChildEventListener(favoritesListener);
    }

    private void stopListeningFavorites() {
        if (userFavoriteSessionsRef != null) {
            userFavoriteSessionsRef.removeEventListener(favoritesListener);
            userFavoriteSessionsRef = null;
            favoritesListener = null;
            favorites.clear();

            for (final Map.Entry<String, HashSet<ImageButton>> entry : sessionButtons.entrySet()) {
                final String session_id = entry.getKey();
                final HashSet<ImageButton> buttons = entry.getValue();
                for (final ImageButton button : buttons) {
                    updateButton(button, session_id);
                }
            }
        }
    }

    private class MyAuthStateListener implements FirebaseAuth.AuthStateListener {
        @Override
        public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
            user = firebaseAuth.getCurrentUser();
            if (user != null) {
                startListeningFavorites();
            }
            else {
                stopListeningFavorites();
            }
        }
    }


    private class MyFavSessionButtonOnClickListener implements View.OnClickListener {
        private final String sessionId;

        public MyFavSessionButtonOnClickListener(final String session_id) {
            this.sessionId = session_id;
        }

        @Override
        public void onClick(final View view) {
            // Require a currently signed in user in order to toggle favorites
            if (user != null) {
                toggleFavorite();
            }
            else {
                authRequiredListener.onAuthRequired((ImageButton) view, sessionId);
            }
        }

        private void toggleFavorite() {
            boolean is_fav = favorites.contains(sessionId);
            if (is_fav) {
                favorites.remove(sessionId);
                userFavoriteSessionsRef.child(sessionId).removeValue();
            }
            else {
                favorites.add(sessionId);
                userFavoriteSessionsRef.child(sessionId).setValue(true);
            }
        }
    }


    private class MyUserFavoritesListener implements ChildEventListener {
        @Override
        public void onChildAdded(DataSnapshot data, String previousChildName) {
            final String session_id = data.getKey();
            boolean is_fav = data.getValue(Boolean.class);
            if (is_fav) {
                favorites.add(session_id);
            }
            else {
                favorites.remove(session_id);
            }
            updateButtons(session_id);
        }

        @Override
        public void onChildChanged(DataSnapshot data, String previousChildName) {
            final String session_id = data.getKey();
            boolean is_fav = data.getValue(Boolean.class);
            if (is_fav) {
                favorites.add(session_id);
            }
            else {
                favorites.remove(session_id);
            }
            updateButtons(session_id);
        }

        @Override
        public void onChildRemoved(DataSnapshot data) {
            final String session_id = data.getKey();
            favorites.remove(session_id);
            updateButtons(session_id);
        }

        @Override
        public void onChildMoved(DataSnapshot data, String s) {
            // Don't care
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            LOGGER.log(Level.SEVERE, "onCancelled", databaseError.toException());
        }

        private void updateButtons(String session_id) {
            final HashSet<ImageButton> buttons = sessionButtons.get(session_id);
            if (buttons != null) {
                for (final ImageButton button : buttons) {
                    updateButton(button, session_id);
                }
            }
        }
    }

    public interface AuthRequiredListener {
        void onAuthRequired(ImageButton view, String sessionId);
    }

}