package com.marverenic.music.ui.library;

import android.content.Context;
import android.content.Intent;
import androidx.databinding.DataBindingUtil;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.IdRes;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;

import com.marverenic.music.JockeyApplication;
import com.marverenic.music.R;
import com.marverenic.music.data.annotations.StartPage;
import com.marverenic.music.data.store.MediaStoreUtil;
import com.marverenic.music.data.store.PreferenceStore;
import com.marverenic.music.databinding.ActivityLibraryBinding;
import com.marverenic.music.model.Song;
import com.marverenic.music.player.PlayerController;
import com.marverenic.music.ui.BaseLibraryActivity;
import com.marverenic.music.ui.BaseLibraryActivityViewModel.OnBottomSheetStateChangeListener.BottomSheetState;
import com.marverenic.music.ui.about.AboutActivity;
import com.marverenic.music.ui.browse.MusicBrowserFragment;
import com.marverenic.music.ui.library.recentlyadded.RecentlyAddedFragment;
import com.marverenic.music.ui.settings.SettingsActivity;
import com.marverenic.music.utils.UriUtils;

import java.io.File;
import java.util.Collections;
import java.util.List;

import javax.inject.Inject;

import timber.log.Timber;

public class LibraryActivity extends BaseLibraryActivity {

    private static final String ACTION_SHOW_NOW_PLAYING_PAGE = "LibraryActivity.ShowNowPlayingPage";
    private static final String EXTRA_SAVED_PAGE_ID = "LibraryActivity.selectedPageId";

    private ActivityLibraryBinding mBinding;

    @Inject PreferenceStore mPrefStore;
    @Inject PlayerController mPlayerController;

    public static Intent newNowPlayingIntent(Context context) {
        Intent intent = new Intent(context, LibraryActivity.class);
        intent.setAction(ACTION_SHOW_NOW_PLAYING_PAGE);
        return intent;
    }

    @Override
    protected Fragment onCreateFragment(@Nullable Bundle savedInstanceState) {
        if (savedInstanceState == null) {
            int startingPage = mPrefStore.getDefaultPage();
            return createFragmentForInitialPage(startingPage);
        } else {
            int savedPage = savedInstanceState.getInt(EXTRA_SAVED_PAGE_ID, R.id.menu_library_home);
            return createFragmentForSelectedPage(savedPage);
        }
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        JockeyApplication.getComponent(this).inject(this);
        super.onCreate(savedInstanceState);

        onNewIntent(getIntent());

        Fragment fragment = getContentFragment();
        if (fragment instanceof MusicBrowserFragment) {
            setSelectedPage(R.id.menu_library_browse);
        } else if (fragment instanceof RecentlyAddedFragment) {
            setSelectedPage(R.id.menu_library_recently_added);
        } else {
            setSelectedPage(R.id.menu_library_home);
        }
    }

    @Override
    protected void onCreateLayout(@Nullable Bundle savedInstanceState) {
        super.onCreateLayout(savedInstanceState);
        ViewGroup contentViewContainer = findViewById(android.R.id.content);
        View root = contentViewContainer.getChildAt(0);
        contentViewContainer.removeAllViews();

        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_library);
        ViewGroup contentContainer = findViewById(R.id.library_content_container);
        contentContainer.addView(root);

        mBinding.libraryDrawerNavigationView.setNavigationItemSelectedListener(item -> {
            mBinding.libraryDrawerLayout.closeDrawers();
            onNavigationItemSelected(item.getItemId());
            return true;
        });
    }

    @Override
    public void onNewIntent(Intent intent) {
        if (intent.getAction() == null) {
            return;
        }

        if (intent.getAction().equals(ACTION_SHOW_NOW_PLAYING_PAGE)) {
            expandBottomSheet();
            mBinding.libraryDrawerLayout.closeDrawers();
            // Don't try to process this intent again
            setIntent(new Intent(this, LibraryActivity.class));
            return;
        }

        // Handle incoming requests to play media from other applications
        if (intent.getData() == null) {
            return;
        }

        // If this intent is a music intent, process it
        if (intent.getAction().equals(Intent.ACTION_VIEW)) {
            MediaStoreUtil.promptPermission(this)
                    .subscribe(hasPermission -> {
                        if (hasPermission) {
                            startPlaybackFromUri(intent.getData());
                        }
                    }, throwable -> {
                        Timber.e(throwable, "Failed to start playback from URI %s",
                                intent.getData());
                    });
        }

        // Don't try to process this intent again
        setIntent(new Intent(this, LibraryActivity.class));
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(EXTRA_SAVED_PAGE_ID, getSelectedDrawerItem());
    }

    @IdRes
    private int getSelectedDrawerItem() {
        Menu menu = mBinding.libraryDrawerNavigationView.getMenu();
        for (int i = 0; i < menu.size(); i++) {
            MenuItem item = menu.getItem(i);
            if (item.isChecked()) {
                return item.getItemId();
            }
        }
        return R.id.menu_library_home;
    }

    @Override
    public boolean onSupportNavigateUp() {
        mBinding.libraryDrawerLayout.openDrawer(Gravity.START);
        return true;
    }

    @Override
    public void onBackPressed() {
        if (mBinding.libraryDrawerLayout.isDrawerOpen(Gravity.START)) {
            mBinding.libraryDrawerLayout.closeDrawers();
        } else {
            super.onBackPressed();
        }
    }

    @Override
    public void setSupportActionBar(@Nullable Toolbar toolbar) {
        super.setSupportActionBar(toolbar);
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setHomeAsUpIndicator(R.drawable.ic_nav_menu_24dp);
            actionBar.setDisplayHomeAsUpEnabled(true);
        }
    }

    @Override
    protected void onBottomSheetStateChange(BottomSheetState newState) {
        boolean collapsed = (newState == BottomSheetState.COLLAPSED)
                || (newState == BottomSheetState.HIDDEN);

        mBinding.libraryDrawerLayout.setDrawerLockMode((collapsed)
                        ? DrawerLayout.LOCK_MODE_UNLOCKED
                        : DrawerLayout.LOCK_MODE_LOCKED_CLOSED,
                Gravity.START);
    }

    private void onNavigationItemSelected(@IdRes int itemId) {
        switch (itemId) {
            case R.id.menu_library_settings:
                startActivity(SettingsActivity.newIntent(this));
                return;
            case R.id.menu_library_about:
                startActivity(AboutActivity.newIntent(this));
                return;
        }

        if (setSelectedPage(itemId)) {
            replaceFragment(createFragmentForSelectedPage(itemId));
        }
    }

    // Returns true if this method changed the state of the menu
    private boolean setSelectedPage(@IdRes int itemId) {
        Menu navMenu = mBinding.libraryDrawerNavigationView.getMenu();
        for (int i = 0; i < navMenu.size(); i++) {
            MenuItem menuItem = navMenu.getItem(i);
            if (menuItem.getItemId() == itemId && menuItem.isChecked()) {
                // If the item id hasn't changed, then return early
                return false;
            }

            menuItem.setChecked(navMenu.getItem(i).getItemId() == itemId);
        }
        return true;
    }

    private Fragment createFragmentForInitialPage(@StartPage int startingPage) {
        switch (startingPage) {
            case StartPage.PLAYLISTS:
            case StartPage.SONGS:
            case StartPage.ARTISTS:
            case StartPage.ALBUMS:
            case StartPage.GENRES:
                return LibraryFragment.newInstance();
            case StartPage.BROWSER:
                return MusicBrowserFragment.newInstance();
            case StartPage.RECENTLY_ADDED:
                return RecentlyAddedFragment.newInstance();
            default:
                Timber.w("Attempted to start on illegal page %d. Defaulting to LibraryFragment",
                        startingPage);
                return LibraryFragment.newInstance();
        }
    }

    private Fragment createFragmentForSelectedPage(@IdRes int itemId) {
        switch (itemId) {
            case R.id.menu_library_home:
                return LibraryFragment.newInstance();
            case R.id.menu_library_browse:
                return MusicBrowserFragment.newInstance();
            case R.id.menu_library_recently_added:
                return RecentlyAddedFragment.newInstance();
            default:
                throw new UnsupportedOperationException("Failed to switch to fragment with menu" +
                        " item id " + getResources().getResourceName(itemId));
        }
    }

    private void startPlaybackFromUri(Uri songUri) {
        String songName = UriUtils.getDisplayName(this, songUri);

        List<Song> queue = buildQueueFromFileUri(songUri);
        int position;

        if (queue == null || queue.isEmpty()) {
            queue = buildQueueFromUri(songUri);
            position = findStartingPositionInQueue(songUri, queue);
        } else {
            String path = UriUtils.getPathFromUri(this, songUri);
            //noinspection ConstantConditions This won't be null, because we found data from it
            Uri fileUri = Uri.fromFile(new File(path));
            position = findStartingPositionInQueue(fileUri, queue);
        }

        if (queue.isEmpty()) {
            showSnackbar(getString(R.string.message_play_error_not_found, songName));
        } else {
            startIntentQueue(queue, position);
        }

        expandBottomSheet();
    }

    private List<Song> buildQueueFromFileUri(Uri fileUri) {
        // URI is not a file URI
        String path = UriUtils.getPathFromUri(this, fileUri);
        if (path == null || path.trim().isEmpty()) {
            return Collections.emptyList();
        }

        File file = new File(path);
        String mimeType = getContentResolver().getType(fileUri);
        return MediaStoreUtil.buildSongListFromFile(this, file, mimeType);
    }

    private List<Song> buildQueueFromUri(Uri uri) {
        return Collections.singletonList(Song.fromUri(this, uri));
    }

    private int findStartingPositionInQueue(Uri originalUri, List<Song> queue) {
        for (int i = 0; i < queue.size(); i++) {
            if (queue.get(i).getLocation().equals(originalUri)) {
                return i;
            }
        }

        return 0;
    }

    private void startIntentQueue(List<Song> queue, int position) {
        mPlayerController.setQueue(queue, position);
        mPlayerController.play();
    }

    @Override
    protected int getSnackbarContainerViewId() {
        return R.id.library_pager;
    }

}