package org.mian.gitnex.fragments;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import org.apache.commons.lang3.StringUtils;
import org.gitnex.tea4j.v2.models.NotificationThread;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.IssueDetailActivity;
import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.adapters.NotificationsAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.FragmentNotificationsBinding;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.SimpleCallback;
import org.mian.gitnex.helpers.SnackBar;
import org.mian.gitnex.helpers.contexts.IssueContext;
import org.mian.gitnex.helpers.contexts.RepositoryContext;

/**
 * @author opyale
 * @author M M Arif
 */
public class NotificationsFragment extends Fragment
		implements NotificationsAdapter.OnNotificationClickedListener,
				NotificationsAdapter.OnMoreClickedListener {

	private final List<NotificationThread> notificationThreads = new ArrayList<>();
	private FragmentNotificationsBinding viewBinding;
	private NotificationsAdapter notificationsAdapter;

	private Activity activity;
	private Context context;
	private Menu menu;

	private int pageCurrentIndex = 1;
	private int pageResultLimit;
	private String currentFilterMode = "unread";
	public static String emptyErrorResponse;

	@Override
	public void onCreate(@Nullable Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
	}

	@Nullable @Override
	public View onCreateView(
			@NonNull LayoutInflater inflater,
			@Nullable ViewGroup container,
			@Nullable Bundle savedInstanceState) {

		viewBinding = FragmentNotificationsBinding.inflate(inflater, container, false);
		setHasOptionsMenu(true);

		activity = requireActivity();
		context = getContext();

		pageResultLimit = Constants.getCurrentResultLimit(context);

		notificationsAdapter = new NotificationsAdapter(context, notificationThreads, this, this);

		LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context);

		viewBinding.notifications.setHasFixedSize(true);
		viewBinding.notifications.setLayoutManager(linearLayoutManager);
		viewBinding.notifications.setAdapter(notificationsAdapter);

		viewBinding.notifications.addOnScrollListener(
				new RecyclerView.OnScrollListener() {

					@Override
					public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {

						if (!recyclerView.canScrollVertically(1) && dy != 0) {
							pageCurrentIndex++;
							loadNotifications(true);
						}

						if (currentFilterMode.equalsIgnoreCase("unread")) {
							if (dy > 0 && viewBinding.markAllAsRead.isShown()) {
								viewBinding.markAllAsRead.setVisibility(View.GONE);
							} else if (dy < 0) {
								viewBinding.markAllAsRead.setVisibility(View.VISIBLE);
							}
						}
					}

					@Override
					public void onScrollStateChanged(
							@NonNull RecyclerView recyclerView, int newState) {
						super.onScrollStateChanged(recyclerView, newState);
					}
				});

		viewBinding.markAllAsRead.setOnClickListener(
				v1 ->
						RetrofitClient.getApiInterface(context)
								.notifyReadList(
										null, "false", Arrays.asList("unread", "pinned"), "read")
								.enqueue(
										(SimpleCallback<List<NotificationThread>>)
												(call, voidResponse) -> {
													if (voidResponse.isPresent()
															&& voidResponse.get().isSuccessful()) {
														SnackBar.success(
																context,
																requireActivity()
																		.findViewById(
																				android.R.id
																						.content),
																getString(
																		R.string
																				.markedNotificationsAsRead));
														pageCurrentIndex = 1;
														loadNotifications(false);
													} else {

														if (!emptyErrorResponse.isEmpty()) {
															if (emptyErrorResponse.contains(
																	"205")) {

																SnackBar.success(
																		context,
																		requireActivity()
																				.findViewById(
																						android.R.id
																								.content),
																		getString(
																				R.string
																						.markedNotificationsAsRead));
																pageCurrentIndex = 1;
																loadNotifications(false);
															}
														} else {

															activity.runOnUiThread(
																	() ->
																			SnackBar.error(
																					context,
																					requireActivity()
																							.findViewById(
																									android
																											.R
																											.id
																											.content),
																					getString(
																							R.string
																									.genericError)));
														}
													}
												}));

		viewBinding.pullToRefresh.setOnRefreshListener(
				() -> {
					viewBinding.pullToRefresh.setRefreshing(false);
					pageCurrentIndex = 1;
					loadNotifications(false);
				});

		loadNotifications(true);
		return viewBinding.getRoot();
	}

	private void loadNotifications(boolean append) {

		viewBinding.noDataNotifications.setVisibility(View.GONE);
		viewBinding.progressBar.setVisibility(View.VISIBLE);
		String[] filter =
				currentFilterMode.equals("read")
						? new String[] {"pinned", "read"}
						: new String[] {"pinned", "unread"};

		RetrofitClient.getApiInterface(context)
				.notifyGetList(
						false,
						Arrays.asList(filter),
						null,
						null,
						null,
						pageCurrentIndex,
						pageResultLimit)
				.enqueue(
						(SimpleCallback<List<NotificationThread>>)
								(call1, listResponse) -> {
									if (listResponse.isPresent()
											&& listResponse.get().isSuccessful()
											&& listResponse.get().body() != null) {
										if (!append) {
											notificationThreads.clear();
										}

										if (listResponse.get().body() != null) {
											notificationThreads.addAll(
													Objects.requireNonNull(
															listResponse.get().body()));
										} else {
											notificationsAdapter.setMoreDataAvailable(false);
										}

										if (!append
												|| Objects.requireNonNull(listResponse.get().body())
																.size()
														> 0) {
											notificationsAdapter.notifyDataChanged();
										}
									}

									AppUtil.setMultiVisibility(View.GONE, viewBinding.progressBar);

									if (notificationThreads.isEmpty()) {
										viewBinding.noDataNotifications.setVisibility(View.VISIBLE);
									} else {
										viewBinding.noDataNotifications.setVisibility(View.GONE);
									}

									if (currentFilterMode.equalsIgnoreCase("unread")) {
										if (notificationThreads.isEmpty()) {
											viewBinding.markAllAsRead.setVisibility(View.GONE);
										} else {
											viewBinding.markAllAsRead.setVisibility(View.VISIBLE);
										}
									}
								});
	}

	private void changeFilterMode() {

		int filterIcon =
				currentFilterMode.equalsIgnoreCase("read")
						? R.drawable.ic_filter_closed
						: R.drawable.ic_filter;

		menu.getItem(0).setIcon(filterIcon);

		if (currentFilterMode.equalsIgnoreCase("read")) {
			viewBinding.markAllAsRead.setVisibility(View.GONE);
		} else {
			viewBinding.markAllAsRead.setVisibility(View.VISIBLE);
		}
	}

	@Override
	public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {

		this.menu = menu;
		inflater.inflate(R.menu.filter_menu_notifications, menu);
		changeFilterMode();

		super.onCreateOptionsMenu(menu, inflater);
	}

	@Override
	public boolean onOptionsItemSelected(@NonNull MenuItem item) {

		if (item.getItemId() == R.id.filterNotifications) {

			BottomSheetNotificationsFilterFragment bottomSheetNotificationsFilterFragment =
					new BottomSheetNotificationsFilterFragment();
			bottomSheetNotificationsFilterFragment.show(
					getChildFragmentManager(), "notificationsFilterBottomSheet");
			bottomSheetNotificationsFilterFragment.setOnClickListener(
					(text) -> {
						currentFilterMode = text;
						changeFilterMode();
						pageCurrentIndex = 1;
						loadNotifications(false);
					});
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

	@Override
	public void onNotificationClicked(NotificationThread notificationThread) {

		if (notificationThread.isUnread() && !notificationThread.isPinned()) {
			RetrofitClient.getApiInterface(context)
					.notifyReadThread(String.valueOf(notificationThread.getId()), "read")
					.enqueue(
							(SimpleCallback<NotificationThread>)
									(call, voidResponse) -> {
										// reload without any checks, because Gitea returns a 205
										// and Java expects this to be empty
										// but Gitea send a response -> results in a call of
										// onFailure and no response is present
										// if(voidResponse.isPresent() &&
										// voidResponse.get().isSuccessful()) {
										pageCurrentIndex = 1;
										loadNotifications(false);
										// }
									});
		}

		if (StringUtils.containsAny(
				notificationThread.getSubject().getType().toLowerCase(), "pull", "issue")) {

			RepositoryContext repo =
					new RepositoryContext(
							notificationThread.getRepository().getOwner().getLogin(),
							notificationThread.getRepository().getName(),
							context); // we can't use the repository object here directly because
			// the permissions are missing
			String issueUrl = notificationThread.getSubject().getUrl();

			repo.saveToDB(context);

			Intent intent =
					new IssueContext(
									repo,
									Integer.parseInt(
											issueUrl.substring(issueUrl.lastIndexOf("/") + 1)),
									notificationThread.getSubject().getType())
							.getIntent(context, IssueDetailActivity.class);
			intent.putExtra("openedFromLink", "true");
			startActivity(intent);
		} else if (notificationThread.getSubject().getType().equalsIgnoreCase("repository")) {
			startActivity(
					new RepositoryContext(notificationThread.getRepository(), context)
							.getIntent(context, RepoDetailActivity.class));
		}
	}

	@Override
	public void onMoreClicked(NotificationThread notificationThread) {
		BottomSheetNotificationsFragment bottomSheetNotificationsFragment =
				new BottomSheetNotificationsFragment();
		bottomSheetNotificationsFragment.onAttach(
				context,
				notificationThread,
				() -> {
					pageCurrentIndex = 1;
					loadNotifications(false);
				});
		bottomSheetNotificationsFragment.show(
				getChildFragmentManager(), "notificationsBottomSheet");
	}
}
