package com.alorma.github.ui.activity;

import android.accounts.Account;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ShortcutManager;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import com.alorma.github.AccountsHelper;
import com.alorma.github.R;
import com.alorma.github.StoreCredentials;
import com.alorma.github.sdk.services.notifications.GetNotificationsClient;
import com.alorma.github.ui.ErrorHandler;
import com.alorma.github.ui.activity.base.BaseActivity;
import com.alorma.github.ui.fragment.GeneralPeopleFragment;
import com.alorma.github.ui.fragment.NavigationFragment;
import com.alorma.github.ui.fragment.donate.DonateActivity;
import com.alorma.github.ui.fragment.events.EventsListFragment;
import com.alorma.github.ui.fragment.events.OrgsEventsListFragment;
import com.alorma.github.ui.fragment.gists.AuthUserGistsFragment;
import com.alorma.github.ui.fragment.gists.AuthUserStarredGistsFragment;
import com.alorma.github.ui.fragment.issues.GeneralIssuesListFragment;
import com.alorma.github.ui.fragment.orgs.OrgsMembersFragment;
import com.alorma.github.ui.fragment.orgs.OrgsReposFragment;
import com.alorma.github.ui.fragment.repos.GeneralReposFragment;
import com.alorma.github.ui.utils.DrawerImage;
import com.alorma.github.utils.AccountUtils;
import com.appsee.Appsee;
import com.mikepenz.actionitembadge.library.ActionItemBadge;
import com.mikepenz.actionitembadge.library.utils.BadgeStyle;
import com.mikepenz.google_material_typeface_library.GoogleMaterial;
import com.mikepenz.iconics.IconicsDrawable;
import com.mikepenz.materialdrawer.AccountHeader;
import com.mikepenz.materialdrawer.AccountHeaderBuilder;
import com.mikepenz.materialdrawer.Drawer;
import com.mikepenz.materialdrawer.DrawerBuilder;
import com.mikepenz.materialdrawer.holder.StringHolder;
import com.mikepenz.materialdrawer.model.DividerDrawerItem;
import com.mikepenz.materialdrawer.model.ExpandableDrawerItem;
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
import com.mikepenz.materialdrawer.model.ProfileDrawerItem;
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem;
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
import com.mikepenz.materialdrawer.util.DrawerImageLoader;
import com.mikepenz.octicons_typeface_library.Octicons;
import core.User;
import core.notifications.Notification;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

public class MainActivity extends BaseActivity implements NavigationFragment.NavigationCallback {

  public static final String NAVIGATION = "NAVIGATION";

  private Account selectedAccount;
  private Fragment lastUsedFragment;
  private Drawer resultDrawer;
  private int notificationsSizeCount = 0;
  private NavigationFragment navigationFragment;
  private AccountHeader accountHeader;
  private Map<String, List<IDrawerItem>> drawerItems;

  public static void startActivity(Activity context) {
    Intent intent = new Intent(context, MainActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    context.startActivity(intent);
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.generic_toolbar_responsive);

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    checkGoodBye();
  }

  private void checkGoodBye() {
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
    if (preferences.getBoolean("GOOD_BYE", true)) {

      Intent intent = new Intent(this, GoodByeActivity.class);
      startActivity(intent);

      preferences.edit().putBoolean("GOOD_BYE", false).apply();
    }
  }

  @Override
  public void onStart() {
    super.onStart();

    if (resultDrawer == null) {
      List<Account> accounts = getAccounts();
      if (!accounts.isEmpty()) {
        selectedAccount = accounts.get(0);
        createDrawer();
        selectAccount(selectedAccount);

        if (getIntent() != null && getIntent().getExtras() != null && getIntent().getExtras().containsKey(NAVIGATION)) {
          String navigation = getIntent().getStringExtra(NAVIGATION);
          if (navigation != null) {
            if (navigation.equals(getString(R.string.shortcut_id_events))) {
              onUserEventsSelected();
            } else if (navigation.equals(getString(R.string.shortcut_id_repositories))) {
              onReposSelected();
            } else if (navigation.equals(getString(R.string.shortcut_id_people))) {
              onPeopleSelected();
            } else if (navigation.equals(getString(R.string.shortcut_id_issues))) {
              onIssuesSelected();
            }
          } else {
            onUserEventsSelected();
          }
        } else {
          onUserEventsSelected();
        }
      }
    }
  }

  @Override
  protected void onStop() {
    navigationFragment.setNavigationCallback(null);
    super.onStop();
  }

  private String getUserExtraName(Account account) {
    String accountName = getNameFromAccount(account);
    String userMail = AccountsHelper.getUserMail(this, account);
    String userName = AccountsHelper.getUserName(this, account);
    if (!TextUtils.isEmpty(userMail)) {
      return userMail;
    } else if (!TextUtils.isEmpty(userName)) {
      return userName;
    }
    return accountName;
  }

  private String getNameFromAccount(Account account) {
    return new AccountUtils().getNameFromAccount(account.name);
  }

  private void createDrawer() {
    accountHeader = buildHeader();
    DrawerBuilder drawer = new DrawerBuilder();
    drawer.withActivity(this);
    drawer.withToolbar(getToolbar());
    drawer.withAccountHeader(accountHeader, true);

    List<IDrawerItem> userItems = getUserDrawerItems();

    for (IDrawerItem userItem : userItems) {
      drawer.addDrawerItems(userItem);
    }

    List<IDrawerItem> allProfilesItems = getStickyDrawerItems();
    for (IDrawerItem allProfilesItem : allProfilesItems) {
      drawer.addStickyDrawerItems(allProfilesItem);
    }

    Drawer.OnDrawerItemClickListener drawerListener = (view, position, drawerItem) -> {
      if (drawerItem != null) {
        long identifier = drawerItem.getIdentifier();
        switch ((int) identifier) {
          case R.id.nav_drawer_notifications:
            openNotifications();
            break;
          case R.id.nav_drawer_settings:
            onSettingsSelected();
            break;
          case R.id.nav_drawer_donate:
            onDonateSelected();
            break;
          case R.id.nav_drawer_sign_out:
            signOut();
            return true;
        }
      }
      return false;
    };

    drawer.withOnDrawerItemClickListener(drawerListener);
    resultDrawer = drawer.build();
    resultDrawer.setSelection(R.id.nav_drawer_events);
  }

  private List<IDrawerItem> getUserDrawerItems() {
    int iconColor = ContextCompat.getColor(this, R.color.icons);

    List<IDrawerItem> items = new ArrayList<>();

    items.add(new PrimaryDrawerItem().withName(R.string.menu_events)
        .withIcon(Octicons.Icon.oct_calendar)
        .withIconColor(iconColor)
        .withIdentifier(R.id.nav_drawer_events)
        .withOnDrawerItemClickListener((view, position, drawerItem) -> {
          onUserEventsSelected();
          return false;
        }));
    items.add(new PrimaryDrawerItem().withName(R.string.navigation_general_repositories)
        .withIcon(Octicons.Icon.oct_repo)
        .withIconColor(iconColor)
        .withIdentifier(R.id.nav_drawer_repositories)
        .withOnDrawerItemClickListener((view, position, drawerItem) -> {
          onReposSelected();
          return false;
        }));
    items.add(new PrimaryDrawerItem().withName(R.string.navigation_people)
        .withIcon(Octicons.Icon.oct_organization)
        .withIconColor(iconColor)
        .withIdentifier(R.id.nav_drawer_people)
        .withOnDrawerItemClickListener((view, position, drawerItem) -> {
          onPeopleSelected();
          return false;
        }));
    items.add(new PrimaryDrawerItem().withName(R.string.navigation_issues)
        .withIcon(Octicons.Icon.oct_issue_opened)
        .withIconColor(iconColor)
        .withIdentifier(R.id.nav_drawer_issues)
        .withOnDrawerItemClickListener((view, position, drawerItem) -> {
          onIssuesSelected();
          return false;
        }));

    PrimaryDrawerItem myGistsDrawerItem = new PrimaryDrawerItem().withName(R.string.navigation_my_gists)
        .withIdentifier(R.id.nav_drawer_gists)
        .withLevel(2)
        .withOnDrawerItemClickListener((view, position, drawerItem) -> {
          onGistsSelected();
          return false;
        });
    PrimaryDrawerItem starredGistsDrawerItem = new PrimaryDrawerItem().withName(R.string.navigation_gists_starred)
        .withIdentifier(R.id.nav_drawer_gists_starred)
        .withLevel(2)
        .withOnDrawerItemClickListener((view, position, drawerItem) -> {
          onStarredGistsSelected();
          return false;
        });
    items.add(new ExpandableDrawerItem().withName(R.string.navigation_gists)
        .withSubItems(myGistsDrawerItem, starredGistsDrawerItem)
        .withIcon(Octicons.Icon.oct_gist)
        .withIconColor(iconColor)
        .withSelectable(false));

    return items;
  }

  private List<IDrawerItem> getStickyDrawerItems() {
    int iconColor = ContextCompat.getColor(this, R.color.icons);

    List<IDrawerItem> items = new ArrayList<>();
    items.add(new SecondaryDrawerItem().withName(R.string.menu_enable_notifications)
        .withIdentifier(R.id.nav_drawer_notifications)
        .withSelectable(false)
        .withIcon(Octicons.Icon.oct_bell)
        .withIconColor(iconColor));

    items.add(new SecondaryDrawerItem().withName(R.string.navigation_settings)
        .withIcon(Octicons.Icon.oct_gear)
        .withIconColor(iconColor)
        .withIdentifier(R.id.nav_drawer_settings)
        .withSelectable(false));

    items.add(new SecondaryDrawerItem().withName(R.string.action_donate)
        .withIcon(Octicons.Icon.oct_heart)
        .withIconColor(iconColor)
        .withIdentifier(R.id.nav_drawer_donate)
        .withSelectable(false));

    items.add(new DividerDrawerItem());

    items.add(new SecondaryDrawerItem().withName(R.string.navigation_sign_out)
        .withIcon(Octicons.Icon.oct_sign_out)
        .withIconColor(iconColor)
        .withIdentifier(R.id.nav_drawer_sign_out)
        .withSelectable(false));

    return items;
  }

  private AccountHeader buildHeader() {
    DrawerImageLoader.init(new DrawerImage());

    AccountHeaderBuilder headerBuilder = new AccountHeaderBuilder().withActivity(this).withHeaderBackground(R.color.md_grey_600);

    headerBuilder.withOnAccountHeaderListener((view, profile, current) -> {
      if (current) {
        User user = new User();
        user.setLogin(profile.getName().getText());
        Intent launcherIntent = ProfileActivity.createLauncherIntent(MainActivity.this, selectedAccount);
        startActivity(launcherIntent);
        return true;
      } else {
        if (profile instanceof ProfileDrawerItem) {
          List<IDrawerItem> subItems = drawerItems.get(profile.getName().getText());
          if (subItems != null && !subItems.isEmpty()) {
            resultDrawer.removeAllItems();
            for (IDrawerItem subItem : subItems) {
              resultDrawer.addItems(subItem);
            }
            try {
              ((PrimaryDrawerItem) subItems.get(0)).getOnDrawerItemClickListener().onItemClick(null, 0, subItems.get(0));
            } catch (Exception e) {
              e.printStackTrace();
            }
            resultDrawer.setSelection(R.id.nav_drawer_events, true);
          }
        }
        return false;
      }
    });

    ProfileDrawerItem userDrawerItem = getUserDrawerItem();

    drawerItems = new HashMap<>();
    drawerItems.put(userDrawerItem.getName().getText(), getUserDrawerItems());

    userDrawerItem.withSubItems();

    headerBuilder.addProfiles(userDrawerItem);

    return headerBuilder.build();
  }

  @NonNull
  private ProfileDrawerItem getOrganizationProfileDrawerItem(User user) {
    return new ProfileDrawerItem().withName(user.getLogin()).withIcon(getUserAvatarUrl(user.getAvatar(), user.getLogin()));
  }

  private Uri getUserAvatarUrl(String avatar, String name) {
    return Uri.parse(avatar).buildUpon().appendQueryParameter("username", name).build();
  }

  private List<IDrawerItem> getOrganizationProfileSubItems(User user) {
    int iconColor = ContextCompat.getColor(this, R.color.icons);
    List<IDrawerItem> items = new ArrayList<>();
    items.add(new PrimaryDrawerItem().withName("Events")
        .withIcon(Octicons.Icon.oct_calendar)
        .withIconColor(iconColor)
        .withIdentifier(R.id.nav_drawer_events)
        .withOnDrawerItemClickListener((view, position, drawerItem) -> {
          onOrgEventsSelected(user.getLogin());
          return false;
        }));
    items.add(new PrimaryDrawerItem().withName("Repositories")
        .withIcon(Octicons.Icon.oct_repo)
        .withIconColor(iconColor)
        .withOnDrawerItemClickListener((view, position, drawerItem) -> {
          onOrgReposSelected(user.getLogin());
          return false;
        }));
    items.add(new PrimaryDrawerItem().withName("Members")
        .withIcon(Octicons.Icon.oct_organization)
        .withIconColor(iconColor)
        .withOnDrawerItemClickListener((view, position, drawerItem) -> {
          onOrgPeopleSelected(user.getLogin());
          return false;
        }));
    items.add(new PrimaryDrawerItem().withName("Teams")
        .withIcon(Octicons.Icon.oct_jersey)
        .withIconColor(iconColor)
        .withEnabled(false)
        .withOnDrawerItemClickListener((view, position, drawerItem) -> {
          onOrgTeamsSelected(user.getLogin());
          return false;
        }));
    return items;
  }

  private ProfileDrawerItem getUserDrawerItem() {
    String userName = getNameFromAccount(selectedAccount);
    String userAvatar = AccountsHelper.getUserAvatar(this, selectedAccount);
    ProfileDrawerItem userDrawerItem = new ProfileDrawerItem().withName(getUserExtraName(selectedAccount))
        .withEmail(userName)
        .withNameShown(false)
        .withIdentifier(selectedAccount.hashCode());
    if (!TextUtils.isEmpty(userAvatar)) {
      userDrawerItem.withIcon(getUserAvatarUrl(userAvatar, userName));
    }
    return userDrawerItem;
  }

  private void selectAccount(final Account account) {
    boolean changingUser = selectedAccount != null && !getNameFromAccount(selectedAccount).equals(getNameFromAccount(account));
    this.selectedAccount = account;

    Appsee.setUserId(getNameFromAccount(account));

    accountNameProvider.setName(getNameFromAccount(account));

    loadUserOrgs();

    StoreCredentials credentials = new StoreCredentials(MainActivity.this);
    credentials.clear();
    String authToken = AccountsHelper.getUserToken(this, account);

    credentials.storeToken(authToken);
    credentials.storeUsername(getNameFromAccount(account));

    credentials.storeUrl(AccountsHelper.getUrl(this, account));

    String url = AccountsHelper.getUrl(this, account);

    credentials.storeUrl(url);

    if (changingUser) {
      lastUsedFragment = null;
    }
  }

  private void loadUserOrgs() {
    navigationFragment = new NavigationFragment();

    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.add(new NavigationFragment(), "navigation");
    ft.commit();

    navigationFragment.setNavigationCallback(this);
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);

    getMenuInflater().inflate(R.menu.main_menu, menu);
    menu.findItem(R.id.action_search)
        .setIcon(new IconicsDrawable(this, GoogleMaterial.Icon.gmd_search).color(Color.WHITE).sizeDp(24).respectFontBounds(true));

    return true;
  }

  @Override
  public boolean onPrepareOptionsMenu(Menu menu) {
    if (notificationsSizeCount > 0) {
      BadgeStyle badgeStyle =
          new BadgeStyle(BadgeStyle.Style.DEFAULT, R.layout.menu_action_item_badge, getResources().getColor(R.color.accent),
              getResources().getColor(R.color.accent_dark), Color.WHITE, getResources().getDimensionPixelOffset(R.dimen.gapMicro));
      ActionItemBadge.update(this, menu.findItem(R.id.action_notifications), Octicons.Icon.oct_bell, badgeStyle, notificationsSizeCount);
    } else {
      ActionItemBadge.hide(menu.findItem(R.id.action_notifications));
    }

    return super.onPrepareOptionsMenu(menu);
  }

  @Override
  protected void onResume() {
    super.onResume();
    checkNotifications();
  }

  private void checkNotifications() {
    GetNotificationsClient client = new GetNotificationsClient();
    client.observable()
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Subscriber<List<Notification>>() {
          @Override
          public void onCompleted() {

          }

          @Override
          public void onError(Throwable e) {

          }

          @Override
          public void onNext(List<Notification> notifications) {
            notificationsSizeCount = notifications.size();
            invalidateOptionsMenu();
          }
        });
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {

    if (item.getItemId() == R.id.action_search) {
      Intent intent = SearchActivity.launchIntent(this);
      startActivity(intent);
    } else if (item.getItemId() == R.id.action_notifications) {
      openNotifications();
    }

    return false;
  }

  private void openNotifications() {
    Intent intent = NotificationsActivity.launchIntent(this);
    startActivity(intent);
  }

  @TargetApi(Build.VERSION_CODES.M)
  private void tagShortcut(@StringRes int shortcutId) {
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N_MR1) {
      String id = getString(shortcutId);
      ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
      shortcutManager.reportShortcutUsed(id);
    }
  }

  private void setFragment(Fragment fragment) {
    setFragment(fragment, true);
  }

  private void setFragment(Fragment fragment, boolean addToBackStack) {
    try {
      if (fragment != null && getSupportFragmentManager() != null) {
        this.lastUsedFragment = fragment;
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        if (ft != null) {
          ft.replace(R.id.content, fragment);
          if (addToBackStack) {
            ft.addToBackStack("navigation");
          }
          ft.commit();
        }
      }
    } catch (Exception e) {
      ErrorHandler.onError(this, "MainActivity.setFragment()", e);
    }
  }

  public void onDonateSelected() {
    Intent intent = new Intent(this, DonateActivity.class);
    startActivity(intent);
  }

  public boolean onReposSelected() {
    setFragment(GeneralReposFragment.newInstance(), false);
    tagShortcut(R.string.shortcut_id_repositories);
    return true;
  }

  public boolean onPeopleSelected() {
    setFragment(GeneralPeopleFragment.newInstance(), false);
    tagShortcut(R.string.shortcut_id_people);
    return false;
  }

  public boolean onIssuesSelected() {
    setFragment(GeneralIssuesListFragment.newInstance(), false);
    tagShortcut(R.string.shortcut_id_issues);
    return false;
  }

  public boolean onGistsSelected() {
    AuthUserGistsFragment gistsFragment = AuthUserGistsFragment.newInstance();
    setFragment(gistsFragment);
    return false;
  }

  public boolean onStarredGistsSelected() {
    AuthUserStarredGistsFragment gistsFragment = AuthUserStarredGistsFragment.newInstance();
    setFragment(gistsFragment);
    return false;
  }

  public boolean onUserEventsSelected() {
    String user = new StoreCredentials(this).getUserName();
    if (user != null) {
      setFragment(EventsListFragment.newInstance(user), false);
    }
    tagShortcut(R.string.shortcut_id_events);
    return true;
  }

  public void onOrgEventsSelected(String orgName) {
    OrgsEventsListFragment orgsEventsListFragment = OrgsEventsListFragment.newInstance(orgName);
    setFragment(orgsEventsListFragment, true);
  }

  public void onOrgReposSelected(String orgName) {
    OrgsReposFragment orgsReposFragment = OrgsReposFragment.newInstance(orgName);
    setFragment(orgsReposFragment, true);
  }

  public void onOrgPeopleSelected(String orgName) {
    OrgsMembersFragment orgsMembersFragment = OrgsMembersFragment.newInstance(orgName);
    setFragment(orgsMembersFragment, true);
  }

  public void onOrgTeamsSelected(String orgName) {

  }

  public boolean onSettingsSelected() {
    Intent intent = new Intent(this, SettingsActivity.class);
    startActivity(intent);
    return false;
  }

  public void signOut() {
    if (selectedAccount != null) {
      removeAccount(selectedAccount, () -> {
        StoreCredentials storeCredentials = new StoreCredentials(MainActivity.this);
        storeCredentials.clear();

        Intent intent = new Intent(MainActivity.this, SplashActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        startActivity(intent);
        finish();
      });
    }
  }

  @Override
  public void onBackPressed() {
    if (resultDrawer != null && resultDrawer.isDrawerOpen()) {
      resultDrawer.closeDrawer();
    } else {
      if (lastUsedFragment instanceof EventsListFragment || lastUsedFragment instanceof OrgsEventsListFragment) {
        finish();
      } else if (resultDrawer != null) {
        StringHolder name = accountHeader.getActiveProfile().getEmail();
        if (name == null) {
          name = accountHeader.getActiveProfile().getName();
        }

        String nameForAccount = new AccountUtils().getNameFromAccount(selectedAccount.name);
        boolean isCurrentUser = nameForAccount != null && nameForAccount.equals(name.getText());
        if (isCurrentUser) {
          onUserEventsSelected();
        } else {
          onOrgEventsSelected(name.getText());
        }
      }
    }
  }

  @Override
  public void onOrganizationsLoaded(List<User> organizations) {
    if (accountHeader != null) {
      for (User organization : organizations) {
        ProfileDrawerItem drawerItem = getOrganizationProfileDrawerItem(organization);
        if (!drawerItems.containsKey(drawerItem.getName().getText())) {
          drawerItems.put(drawerItem.getName().getText(), getOrganizationProfileSubItems(organization));
          drawerItem.withSubItems();
          accountHeader.addProfiles(drawerItem);
        }
      }
    }
  }
}