package org.edx.mobile.view;

import androidx.databinding.DataBindingUtil;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SearchView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.URLUtil;
import android.widget.TextView;

import org.edx.mobile.BuildConfig;
import org.edx.mobile.R;
import org.edx.mobile.databinding.FragmentWebviewDiscoveryBinding;
import org.edx.mobile.event.DiscoveryTabSelectedEvent;
import org.edx.mobile.event.MainDashboardRefreshEvent;
import org.edx.mobile.event.NetworkConnectivityChangeEvent;
import org.edx.mobile.http.notifications.FullScreenErrorNotification;
import org.edx.mobile.model.api.EnrolledCoursesResponse;
import org.edx.mobile.util.links.DefaultActionListener;

import java.util.HashMap;
import java.util.Map;

import de.greenrobot.event.EventBus;

import static org.edx.mobile.util.UrlUtil.QUERY_PARAM_SEARCH;
import static org.edx.mobile.util.UrlUtil.buildUrlWithQueryParams;

/**
 * An abstract fragment providing basic functionality of searching the webpage via toolbar searchview.
 */
public abstract class WebViewDiscoverFragment extends BaseWebViewFragment {
    private static final String INSTANCE_CURRENT_DISCOVER_URL = "current_discover_url";

    protected FragmentWebviewDiscoveryBinding binding;
    private SearchView searchView;
    private ToolbarCallbacks toolbarCallbacks;

    protected abstract String getSearchUrl();

    protected abstract int getQueryHint();

    protected abstract boolean isSearchEnabled();

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_webview_discovery, container, false);
        return binding.getRoot();
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        setWebViewActionListener();
        // Check for search query in extras
        String searchQueryExtra = null;
        String searchUrl = null;

        if (savedInstanceState != null) {
            searchUrl = savedInstanceState.getString(INSTANCE_CURRENT_DISCOVER_URL, null);
        }
        if (searchUrl == null && getArguments() != null) {
            searchQueryExtra = getArguments().getString(Router.EXTRA_SEARCH_QUERY);
        }

        if (searchQueryExtra != null) {
            initSearch(searchQueryExtra);
        } else {
            loadUrl(searchUrl == null || !URLUtil.isValidUrl(searchUrl) ? getInitialUrl() : searchUrl);
        }
        if (!EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().register(this);
        }
    }

    public void setWebViewActionListener() {
        client.setActionListener(new DefaultActionListener(getActivity(), progressWheel,
                new DefaultActionListener.EnrollCallback() {
                    @Override
                    public void onResponse(@NonNull EnrolledCoursesResponse course) {

                    }

                    @Override
                    public void onFailure(@NonNull Throwable error) {
                    }

                    @Override
                    public void onUserNotLoggedIn(@NonNull String courseId, boolean emailOptIn) {
                    }
                }));
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        if (URLUtil.isValidUrl(binding.webview.getUrl())) {
            // Saving the url to maintain the filtered state of the screen if user has applied it
            outState.putString(INSTANCE_CURRENT_DISCOVER_URL, binding.webview.getUrl());
        }
        super.onSaveInstanceState(outState);
    }

    @Override
    public FullScreenErrorNotification initFullScreenErrorNotification() {
        return new FullScreenErrorNotification(binding.llContent);
    }

    private void initSearch(@NonNull String query) {
        final String baseUrl = getInitialUrl();
        final Map<String, String> queryParams = new HashMap<>();
        queryParams.put(QUERY_PARAM_SEARCH, query);
        loadUrl(buildUrlWithQueryParams(logger, baseUrl, queryParams));
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        toolbarCallbacks = getActivity() instanceof ToolbarCallbacks ?
                (ToolbarCallbacks) getActivity() : null;
        initSearchView();
    }

    private SearchView.OnQueryTextListener onQueryTextListener = new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            initSearch(query);
            searchView.onActionViewCollapsed();
            final boolean isLoggedIn = environment.getLoginPrefs().getUsername() != null;
            environment.getAnalyticsRegistry().trackCoursesSearch(query, isLoggedIn, BuildConfig.VERSION_NAME);
            return true;
        }

        @Override
        public boolean onQueryTextChange(String newText) {
            return false;
        }
    };

    private SearchView.OnFocusChangeListener onFocusChangeListener = new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View view, boolean queryTextFocused) {
            if (!queryTextFocused) {
                updateTitleVisibility(View.VISIBLE);
                searchView.onActionViewCollapsed();
            } else {
                updateTitleVisibility(View.GONE);
            }
        }
    };

    private void initSearchView() {
        searchView = toolbarCallbacks.getSearchView();
        if (getUserVisibleHint()) {
            searchView.setQueryHint(getResources().getString(getQueryHint()));
            searchView.setOnQueryTextListener(onQueryTextListener);
            searchView.setOnQueryTextFocusChangeListener(onFocusChangeListener);
        }
        if (searchView.hasFocus()) {
            updateTitleVisibility(View.GONE);
        }
    }

    private void updateTitleVisibility(int visibility) {
        final TextView titleView = toolbarCallbacks != null ? toolbarCallbacks.getTitleView() : null;
        if (titleView != null) {
            titleView.setVisibility(visibility);
        }
    }

    @NonNull
    protected String getInitialUrl() {
        return URLUtil.isValidUrl(binding.webview.getUrl()) ?
                binding.webview.getUrl() : getSearchUrl();
    }

    @SuppressWarnings("unused")
    public void onEvent(MainDashboardRefreshEvent event) {
        loadUrl(getInitialUrl());
    }

    @Override
    public void onRefresh() {
        EventBus.getDefault().post(new MainDashboardRefreshEvent());
    }

    @SuppressWarnings("unused")
    public void onEvent(NetworkConnectivityChangeEvent event) {
        onNetworkConnectivityChangeEvent(event);
    }

    @SuppressWarnings("unused")
    public void onEventMainThread(@NonNull DiscoveryTabSelectedEvent event) {
        // OfflineSupportBaseFragment.setUserVisibleHint(*) should be called automatically whenever
        // the fragment visibility is changed to user but in the case of WebViewDiscoverCoursesFragment
        // & WebViewDiscoverProgramsFragment setUserVisibleHint is not getting called on tab selection
        // that's why we need to call it manually.
        if (!isHidden()) {
            setUserVisibleHint(getUserVisibleHint());
        }
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        onFragmentVisibilityChange(isVisibleToUser);
    }

    @Override
    public void onHiddenChanged(boolean hidden) {
        super.onHiddenChanged(hidden);
        onFragmentVisibilityChange(!hidden);
    }

    private void onFragmentVisibilityChange(boolean isVisible) {
        if (searchView != null) {
            if (isVisible && isSearchEnabled()) {
                searchView.setVisibility(View.VISIBLE);
                searchView.setQueryHint(getResources().getString(getQueryHint()));
                searchView.setOnQueryTextListener(onQueryTextListener);
                searchView.setOnQueryTextFocusChangeListener(onFocusChangeListener);
            } else {
                searchView.setVisibility(View.GONE);
            }
        }
    }

    @Override
    protected boolean isShowingFullScreenError() {
        return errorNotification != null && errorNotification.isShowing();
    }
}