package com.blackcj.fitdata.activity;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.TabLayout;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.SearchView;
import android.transition.ChangeBounds;
import android.transition.Transition;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;

import com.blackcj.fitdata.Utilities;
import com.blackcj.fitdata.adapter.TabPagerAdapter;
import com.blackcj.fitdata.R;
import com.blackcj.fitdata.database.DataManager;
import com.blackcj.fitdata.fragment.PageFragment;
import com.blackcj.fitdata.fragment.SettingsFragment;
import com.blackcj.fitdata.model.UserPreferences;
import com.blackcj.fitdata.model.Workout;
import com.blackcj.fitdata.service.BackgroundRefreshService;
import com.getbase.floatingactionbutton.FloatingActionsMenu;
import com.google.android.gms.fitness.data.DataSet;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;
import java.util.Calendar;
import java.util.Date;

import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;

/**
 * This sample demonstrates how to use the History API of the Google Fit platform to insert data,
 * query against existing data, and remove data. It also demonstrates how to authenticate
 * a user with Google Play Services and how to properly represent data in a {@link DataSet}.
 *
 * https://developers.google.com/fit/android/get-api-key
 */
@SuppressWarnings("WeakerAccess") // Butterknife requires public reference of injected views
public class MainActivity extends BaseActivity implements SearchView.OnQueryTextListener,
        FragmentManager.OnBackStackChangedListener, AppBarLayout.OnOffsetChangedListener,
        IMainActivityCallback, DataManager.IDataManager, FloatingActionsMenu.OnFloatingActionsMenuUpdateListener {

    private static final String TAG = "MainActivity";
    public static final  String RECEIVER_TAG = "MainActivityReceiver";

    public static final String ACTION_ADD_ACTIVITY = "com.blackcj.fitdata.ADD_ACTIVITY";
    public static boolean active = false;
    protected DataManager mDataManager;

    private TabPagerAdapter mAdapter;

    @Bind(R.id.coordinatorLayout) CoordinatorLayout coordinatorLayout;
    @Bind(R.id.appBarLayout) AppBarLayout appBarLayout;
    @Bind(R.id.viewPager) ViewPager mViewPager;
    @Bind(R.id.main_overlay) View overlay;
    @Bind(R.id.floatingActionMenu) FloatingActionsMenu floatingActionMenu;
    @Bind(R.id.floatingActionButton) FloatingActionButton fab;


    ///////////////////////////////////////
    // LIFE CYCLE
    ///////////////////////////////////////

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Transition fade = new ChangeBounds();
        fade.excludeTarget(android.R.id.navigationBarBackground, true);
        getWindow().setExitTransition(fade);
        getWindow().setEnterTransition(fade);

        setActionBarIcon(R.drawable.barchart_icon);
        ButterKnife.bind(this);

        mDataManager = DataManager.getInstance(this);

        mAdapter = new TabPagerAdapter(this.getSupportFragmentManager());

        TabLayout tabLayout = (TabLayout) findViewById(R.id.tabLayout);
        mViewPager = (ViewPager) findViewById(R.id.viewPager);
        mViewPager.setAdapter(mAdapter);

        if (tabLayout != null) {
            tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
            tabLayout.setupWithViewPager(mViewPager);
            tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER);
            tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
                @Override
                public void onTabSelected(TabLayout.Tab tab) {
                    mViewPager.setCurrentItem(tab.getPosition());
                    //animateFab(tab.getPosition());
                }

                @Override
                public void onTabUnselected(TabLayout.Tab tab) {

                }

                @Override
                public void onTabReselected(TabLayout.Tab tab) {

                }
            });
        }

        mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));


        overlay.setVisibility(View.GONE);

        overlay.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                floatingActionMenu.collapse();
                return true;
            }
        });

        floatingActionMenu.setOnFloatingActionsMenuUpdateListener(this);

        Intent intent = new Intent("com.blackcj.fitdata.START_REFRESH");
        sendBroadcast(intent);

        if (ACTION_ADD_ACTIVITY.equals(getIntent().getAction())) {
            // Invoked via the manifest shortcut.
            AddEntryActivity.launch(MainActivity.this, 3);
        }
    }

    @Override
    protected int getLayoutResource() {
        return R.layout.activity_main;
    }

    @Override
    protected void onResume() {
        super.onResume();
        overlay.setAlpha(0f);
        floatingActionMenu.collapse();
    }

    @Override
    public void onStart() {
        super.onStart();
        active = true;
        mDataManager = DataManager.getInstance(this);
        mDataManager.addListener(this);
        mDataManager.setContext(this);
        mDataManager.connect();
        appBarLayout.addOnOffsetChangedListener(this);
        getSupportFragmentManager().addOnBackStackChangedListener(this);

    }

    @Override
    protected void onStop() {
        active = false;
        mDataManager.removeListener(this);
        mDataManager.disconnect();
        appBarLayout.removeOnOffsetChangedListener(this);
        getSupportFragmentManager().removeOnBackStackChangedListener(this);
        super.onStop();
    }

    @Override
    protected void onPause() {
        floatingActionMenu.collapse();
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        mAdapter.destroy();
        //mDataManager.disconnect();
        super.onDestroy();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == DataManager.REQUEST_OAUTH) {
            mDataManager.authInProgress = false;
            if (resultCode == RESULT_OK) {
                // Make sure the app is not already connected or attempting to connect
                mDataManager.connect();
            }
        }
    }

    int index = 0;

    @Override
    public void onOffsetChanged(AppBarLayout appBarLayout, int i) {
        index = i;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        final int action = MotionEventCompat.getActionMasked(ev);
        switch (action) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                PageFragment pageFragment = mAdapter.getFragment(mViewPager.getCurrentItem());
                if (pageFragment != null) {
                    if (index == 0) {
                        pageFragment.setSwipeToRefreshEnabled(true);
                    } else {
                        pageFragment.setSwipeToRefreshEnabled(false);
                    }
                }
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public void onBackStackChanged()
    {
        FragmentManager manager = getSupportFragmentManager();
        if (manager != null && manager.getBackStackEntryCount() == 0 && overlay.getVisibility() == View.VISIBLE) {
            overlay.setAlpha(0f);

            floatingActionMenu.collapse();
        }
    }

    ///////////////////////////////////////
    // OPTIONS MENU
    ///////////////////////////////////////

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        super.onPrepareOptionsMenu(menu);
        if (menu != null) {
            MenuItem mSearchItem = menu.findItem(R.id.search_participants);
            SearchView mSearchView = (SearchView) MenuItemCompat.getActionView(mSearchItem);
            mSearchView.setOnQueryTextListener(this);
            mSearchView.setQueryHint("Search");
            MenuItemCompat.setOnActionExpandListener(mSearchItem, new MenuItemCompat.OnActionExpandListener() {
                @Override
                public boolean onMenuItemActionExpand(MenuItem item) {
                    return true;
                }

                @Override
                public boolean onMenuItemActionCollapse(MenuItem item) {
                    return true;
                }
            });
        }
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        boolean loadComplete = UserPreferences.getBackgroundLoadComplete(this);
        long lastSync = UserPreferences.getLastSync(this);
        switch (id) {
            case R.id.action_history:
                RecentActivity.launch(MainActivity.this);
                break;
            case R.id.action_reload_data:
                if (loadComplete) {
                    long syncStart = lastSync - (1000 * 60 * 60 * 24 * 7);
                    UserPreferences.setLastSync(this, syncStart);
                    startService(new Intent(this, BackgroundRefreshService.class));
                }
                return true;
            case R.id.action_settings:
                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                transaction.setCustomAnimations(R.anim.enter_anim, R.anim.exit_anim, R.anim.enter_anim, R.anim.exit_anim);
                transaction.add(R.id.top_container, new SettingsFragment());
                transaction.addToBackStack("settings");
                transaction.commit();
                return true;
            case android.R.id.home:
                getSupportFragmentManager().popBackStack();
                return true;
            case R.id.action_import:
                if (loadComplete) {
                    restoreDatabase();
                    //long syncStart = lastSync - (1000 * 60 * 60 * 24 * 4);
                    //UserPreferences.setLastSync(this, syncStart);
                    //startService(new Intent(this, BackgroundRefreshService.class));

                }
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private static final int REQUEST_WRITE_STORAGE = 112;

    /**
     * Used for debugging to restore some meaningful data
     */
    public void restoreDatabase() {
        boolean hasPermission = (ContextCompat.checkSelfPermission(this,
                android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
        if (!hasPermission) {
            ActivityCompat.requestPermissions(this,
                    new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    REQUEST_WRITE_STORAGE);
        }
        Log.d("MainActivity", "Restoring database.");
        try {
            File sd = Environment.getExternalStorageDirectory();
            File data = Environment.getDataDirectory();

            if (sd.canWrite()) {
                String backupDBPath = "//data//com.blackcj.fitdata//databases//googlefitexample.db";
                String currentDBPath = "sdcard/backup.db";
                File currentDB = new File(currentDBPath);
                File backupDB = new File(data, backupDBPath);

                if (currentDB.exists()) {
                    FileChannel src = new FileInputStream(currentDB).getChannel();
                    FileChannel dst = new FileOutputStream(backupDB).getChannel();
                    dst.transferFrom(src, 0, src.size());
                    src.close();
                    dst.close();
                    Log.d("MainActivity", "Database restored.");
                } else {
                    Log.d("MainActivity", "Database doesn't exist.");
                }
            }else {
                Log.d("MainActivity", "Unable to write file.");
            }
        } catch (Exception e) {
            Log.d("MainActivity", "Exception restoring database");
        }
    }

    ///////////////////////////////////////
    // SEARCH CALLBACKS
    ///////////////////////////////////////

    @Override
    public boolean onQueryTextSubmit(String query) {
        return false;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        mAdapter.filter = newText;
        if (mAdapter.getFragment(mViewPager.getCurrentItem()) != null) {
            mAdapter.getFragment(mViewPager.getCurrentItem()).setFilterText(newText);
        }
        if (mAdapter.getFragment(mViewPager.getCurrentItem() + 1) != null) {
            mAdapter.getFragment(mViewPager.getCurrentItem() + 1).setFilterText(newText);
        }
        if (mAdapter.getFragment(mViewPager.getCurrentItem() - 1) != null) {
            mAdapter.getFragment(mViewPager.getCurrentItem() - 1).setFilterText(newText);
        }
        Log.d("MainActivity", "Query text: " + newText);
        return false;
    }

    @OnClick({R.id.step_button, R.id.bike_button, R.id.run_button, R.id.other_button})
    void showAddEntryFragment(View view) {
        int activityType;
        switch (view.getId()) {
            case R.id.step_button:
                activityType = 0;
                break;
            case R.id.run_button:
                activityType = 1;
                break;
            case R.id.bike_button:
                activityType = 2;
                break;
            default:
                activityType = 3;
        }

        AddEntryActivity.launch(MainActivity.this, activityType);

    }

    ///////////////////////////////////////
    // ACTIVITY CALLBACKS - IMainActivity
    ///////////////////////////////////////

    @Override
    public void insertData(Workout workout) {
        mDataManager.insertData(workout);
    }

    @Override
    public void removeData(Workout workout) {
        mDataManager.deleteWorkout(workout);
    }

    @Override
    public void onConnected() {
        Calendar cal = Calendar.getInstance();
        Date now = new Date();
        cal.setTime(now);
        final long currentTime = cal.getTimeInMillis();

        Context context = getApplicationContext();
        long lastSync = UserPreferences.getLastSync(context);
        long lastStart = UserPreferences.getLastSyncStart(context);
        if (lastSync == 0 && (currentTime - lastStart) >  1000 * 60 * 20) {
            startService(new Intent(this, BackgroundRefreshService.class));
        }
    }

    @Override
    public void onDataChanged(final Utilities.TimeFrame timeFrame) {
        Log.d(TAG, "DATA CHANGED");
        // TODO: Refresh prev / next page too
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (timeFrame == Utilities.TimeFrame.BEGINNING_OF_DAY) {
                    if (mAdapter.getFragment(0) != null) {
                        mAdapter.getFragment(0).refreshData();
                    }
                } else if (timeFrame == Utilities.TimeFrame.BEGINNING_OF_WEEK) {
                    if (mAdapter.getFragment(1) != null) {
                        mAdapter.getFragment(1).refreshData();
                    }
                } else {
                    if (mAdapter.getFragment(mViewPager.getCurrentItem()) != null) {
                        mAdapter.getFragment(mViewPager.getCurrentItem()).refreshData();
                    }
                    if (mAdapter.getFragment(mViewPager.getCurrentItem() + 1) != null) {
                        mAdapter.getFragment(mViewPager.getCurrentItem() + 1).refreshData();
                    }
                    if (mAdapter.getFragment(mViewPager.getCurrentItem() - 1) != null) {
                        mAdapter.getFragment(mViewPager.getCurrentItem() - 1).refreshData();
                    }
                }
            }
        });
    }

    @Override
    public void onDataComplete() {

    }

    public void setStepCounting(boolean active) {
        if (mDataManager != null && UserPreferences.getCountSteps(this) != active) {
            mDataManager.setStepCounting(active);
        }
    }

    public void setActivityTracking(boolean active) {
        if (mDataManager != null && UserPreferences.getActivityTracking(this) != active) {
            mDataManager.setActivityTracking(active);
        }
    }

    @Override
    public void quickDataRead() {
        startService(new Intent(this, BackgroundRefreshService.class));
    }

    @Override
    public void launch(View transitionView, Workout workout) {
        getWindow().setExitTransition(null);
        DetailActivity.launch(MainActivity.this, transitionView, workout);
    }

    ///////////////////////////////////////
    // FLOATING MENU
    ///////////////////////////////////////

    @Override
    public void onMenuExpanded() {
        overlay.clearAnimation();
        float viewAlpha = overlay.getAlpha();
        overlay.setVisibility(View.VISIBLE);

        ValueAnimator fadeAnim = ObjectAnimator.ofFloat(overlay, "alpha", viewAlpha, 1f);
        fadeAnim.setDuration(200L);

        fadeAnim.start();
    }

    @Override
    public void onMenuCollapsed() {
        overlay.clearAnimation();
        float viewAlpha = overlay.getAlpha();
        ValueAnimator fadeAnim = ObjectAnimator.ofFloat(overlay, "alpha", viewAlpha, 0f);
        fadeAnim.setDuration(300L);
        fadeAnim.addListener(new AnimatorListenerAdapter() {
            public void onAnimationEnd(Animator animation) {
                overlay.setVisibility(View.GONE);
            }
        });

        fadeAnim.start();
    }
}