package com.alorma.github.ui.fragment.issues;

import android.animation.Animator;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import com.alorma.github.R;
import com.alorma.github.injector.component.ApiComponent;
import com.alorma.github.injector.component.ApplicationComponent;
import com.alorma.github.injector.component.DaggerApiComponent;
import com.alorma.github.injector.module.ApiModule;
import com.alorma.github.injector.module.issues.IssuesModule;
import com.alorma.github.presenter.issue.IssuesPresenter;
import com.alorma.github.sdk.bean.info.IssueInfo;
import com.alorma.github.sdk.bean.info.RepoInfo;
import com.alorma.github.ui.activity.IssueDetailActivity;
import com.alorma.github.ui.activity.NewIssueActivity;
import com.alorma.github.ui.activity.PullRequestDetailActivity;
import com.alorma.github.ui.activity.SearchIssuesActivity;
import com.alorma.github.ui.adapter.base.RecyclerArrayAdapter;
import com.alorma.github.ui.fragment.base.LoadingListFragment;
import com.alorma.github.ui.fragment.detail.repo.BackManager;
import com.alorma.github.ui.fragment.detail.repo.PermissionsManager;
import com.alorma.github.ui.fragment.issues.user.IssuesAdapter;
import com.alorma.github.ui.listeners.TitleProvider;
import com.mikepenz.google_material_typeface_library.GoogleMaterial;
import com.mikepenz.iconics.IconicsDrawable;
import com.mikepenz.iconics.typeface.IIcon;
import com.mikepenz.octicons_typeface_library.Octicons;
import core.search.IssuesSearchRequest;
import core.issues.Issue;
import core.repositories.Permissions;
import java.util.List;
import javax.inject.Inject;

public class IssuesListFragment extends LoadingListFragment<IssuesAdapter>
    implements TitleProvider, PermissionsManager, BackManager, com.alorma.github.presenter.View<List<Issue>>,
    RecyclerArrayAdapter.ItemCallback<Issue> {

  @Inject IssuesPresenter presenter;

  private static final String REPO_INFO = "REPO_INFO";
  private static final String FROM_SEARCH = "FROM_SEARCH";

  private static final int ISSUE_REQUEST = 1234;

  private RepoInfo repoInfo;

  private boolean fromSearch = false;

  private int currentFilter = 0;
  private View revealView;

  public static IssuesListFragment newInstance(RepoInfo repoInfo, boolean fromSearch) {
    Bundle bundle = new Bundle();
    bundle.putParcelable(REPO_INFO, repoInfo);
    bundle.putBoolean(FROM_SEARCH, fromSearch);

    IssuesListFragment fragment = new IssuesListFragment();
    fragment.setArguments(bundle);
    return fragment;
  }

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(!fromSearch);
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    return inflater.inflate(R.layout.issues_list_fragment, null, false);
  }

  @Override
  public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    revealView = view.findViewById(R.id.revealView);

    Spinner spinner = (Spinner) view.findViewById(R.id.spinner);
    String[] items = getResources().getStringArray(R.array.issues_filter);
    ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, items);
    spinner.setAdapter(adapter);

    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
      @Override
      public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        if (currentFilter != position) {
          currentFilter = position;

          clear();

          IssuesSearchRequest request = getIssueSearchRequest(position);
          presenter.execute(request);
        }
      }

      @Override
      public void onNothingSelected(AdapterView<?> parent) {

      }
    });
  }

  @Override
  protected void injectComponents(ApplicationComponent applicationComponent) {
    super.injectComponents(applicationComponent);

    ApiComponent apiComponent = DaggerApiComponent.builder().applicationComponent(applicationComponent).apiModule(new ApiModule()).build();

    apiComponent.plus(new IssuesModule()).inject(this);
    presenter.attachView(this);
  }

  @Override
  public void onStop() {
    presenter.detachView();
    super.onStop();
  }

  @Override
  protected int getLightTheme() {
    return R.style.AppTheme_Repository;
  }

  @Override
  protected int getDarkTheme() {
    return R.style.AppTheme_Dark_Repository;
  }

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

    if (revealView != null) {
      revealView.setVisibility(View.INVISIBLE);
    }
  }

  @Override
  public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    super.onCreateOptionsMenu(menu, inflater);
    inflater.inflate(R.menu.issue_list_filter, menu);
  }

  @Override
  public void onPrepareOptionsMenu(Menu menu) {
    super.onPrepareOptionsMenu(menu);

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

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
      case R.id.action_search:
        Intent intent = SearchIssuesActivity.launchIntent(getActivity(), repoInfo);
        startActivity(intent);
        break;
    }
    return super.onOptionsItemSelected(item);
  }

  @Override
  protected void loadArguments() {
    if (getArguments() != null) {
      repoInfo = getArguments().getParcelable(REPO_INFO);
      fromSearch = getArguments().getBoolean(FROM_SEARCH, false);
    }
  }

  @NonNull
  private IssuesSearchRequest getIssueSearchRequest(int status) {
    IssuesSearchRequest builder = new IssuesSearchRequest();
    builder.setIsOpen(status == 0);
    builder.setRepo(repoInfo.name, repoInfo.owner);
    builder.setIsPullRequest(false);
    return builder;
  }

  protected void executeRequest() {
    if (currentFilter == 0 || currentFilter == 1) {
      IssuesSearchRequest builder = getIssueSearchRequest(currentFilter);
      presenter.execute(builder);
    }
  }

  @Override
  protected void executePaginatedRequest(int page) {
    if (currentFilter == 0 || currentFilter == 1) {
      IssuesSearchRequest builder = getIssueSearchRequest(currentFilter);
      presenter.executePaginated(builder);
    }
  }

  protected void onResponse(List<Issue> issues) {
    if (issues.size() > 0) {
      hideEmpty();
      if (refreshing || getAdapter() == null) {
        IssuesAdapter issuesAdapter = new IssuesAdapter(LayoutInflater.from(getActivity()));
        issuesAdapter.addAll(issues);
        issuesAdapter.setCallback(this);
        setAdapter(issuesAdapter);
      } else {
        getAdapter().addAll(issues);
      }
    } else if (getAdapter() == null || getAdapter().getItemCount() == 0) {
      setEmpty();
    } else {
      getAdapter().clear();
      setEmpty();
    }
  }

  @Override
  protected Octicons.Icon getNoDataIcon() {
    return Octicons.Icon.oct_issue_opened;
  }

  @Override
  protected int getNoDataText() {
    return R.string.no_issues_found;
  }

  @Override
  protected boolean useFAB() {
    return !fromSearch && (repoInfo.permissions == null || repoInfo.permissions.pull);
  }

  @Override
  protected void fabClick() {
    super.fabClick();
    if (repoInfo.permissions != null) {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && fab != null) {
        animateRevealFab();
      } else {
        openNewIssueActivity();
      }
    }
  }

  private void openNewIssueActivity() {
    Intent intent = NewIssueActivity.createLauncherIntent(getActivity(), repoInfo);
    startActivityForResult(intent, ISSUE_REQUEST);
  }

  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  private void animateRevealFab() {
    float x = fab.getX() + (fab.getWidth() / 2);
    float y = fab.getY() + (fab.getHeight() / 2);

    int finalRadius = Math.max(revealView.getWidth(), revealView.getHeight());
    Animator anim = ViewAnimationUtils.createCircularReveal(revealView, (int) x, (int) y, fab.getWidth() / 2, finalRadius);
    revealView.setVisibility(View.VISIBLE);
    anim.setDuration(600);
    anim.setInterpolator(new AccelerateInterpolator());
    anim.addListener(new Animator.AnimatorListener() {
      @Override
      public void onAnimationStart(Animator animator) {

      }

      @Override
      public void onAnimationEnd(Animator animator) {
        openNewIssueActivity();
      }

      @Override
      public void onAnimationCancel(Animator animator) {

      }

      @Override
      public void onAnimationRepeat(Animator animator) {

      }
    });
    anim.start();
  }

  @Override
  public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == Activity.RESULT_FIRST_USER) {
      invalidate();
    } else if (requestCode == ISSUE_REQUEST && resultCode == Activity.RESULT_OK) {
      invalidate();
    }
  }

  public void invalidate() {
    onRefresh();
  }

  public void setPermissions(Permissions permissions) {
    if (this.repoInfo != null) {
      this.repoInfo.permissions = permissions;
      checkFAB();
    }
  }

  @Override
  protected Octicons.Icon getFABGithubIcon() {
    return Octicons.Icon.oct_bug;
  }

  @Override
  public int getTitle() {
    return R.string.issues_fragment_title;
  }

  @Override
  public IIcon getTitleIcon() {
    return Octicons.Icon.oct_issue_opened;
  }

  public void clear() {
    if (getAdapter() != null) {
      getAdapter().clear();
    }
  }

  @Override
  public void setPermissions(boolean admin, boolean push, boolean pull) {
    if (this.repoInfo != null) {
      Permissions permissions = new Permissions();
      permissions.admin = admin;
      permissions.push = push;
      permissions.pull = pull;

      setPermissions(permissions);
    }
  }

  @Override
  public boolean onBackPressed() {
    return true;
  }

  public void executeSearch() {
    onRefresh();
  }

  @Override
  protected boolean autoStart() {
    return !fromSearch;
  }

  @Override
  public void setRefreshing() {
    super.setRefreshing();
    startRefresh();
  }

  @Override
  public void showLoading() {

  }

  @Override
  public void hideLoading() {

  }

  @Override
  public void onDataReceived(List<Issue> data, boolean isFromPaginated) {
    onResponse(data);
  }

  @Override
  public void showError(Throwable throwable) {

  }

  @Override
  public void onItemSelected(Issue item) {
    if (item != null) {
      IssueInfo info = new IssueInfo();
      info.repoInfo = repoInfo;
      info.num = item.getNumber();

      if (item.getPullRequest() == null) {
        Intent intent = IssueDetailActivity.createLauncherIntent(getActivity(), info);
        startActivityForResult(intent, ISSUE_REQUEST);
      } else {
        Intent intent = PullRequestDetailActivity.createLauncherIntent(getActivity(), info);
        startActivityForResult(intent, ISSUE_REQUEST);
      }
    }
  }

  public interface SearchClientRequest {
    String request();
  }
}
