package com.gh.gamecenter.common.baselist;

import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

import com.ethanhua.skeleton.SkeletonScreen;
import com.gh.gamecenter.common.R;
import com.gh.gamecenter.common.base.fragment.ToolbarFragment;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.common.view.FixLinearLayoutManager;
import com.gh.gamecenter.common.view.VerticalItemDecoration;
import com.gh.gamecenter.core.HaloApp;
import com.gh.gamecenter.core.utils.NumberUtils;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.Single;

/**
 * Created by khy on 2/12/17.
 */

public abstract class ListFragment<T, VM extends BaseListViewModel /* 该泛型位置对应getViewModelClass */> extends ToolbarFragment implements
        Observer<List<T>>,
        SwipeRefreshLayout.OnRefreshListener,
        OnDataObservable<T> {

    protected RecyclerView mListRv;
    @Nullable
    protected SwipeRefreshLayout mListRefresh;
    @Nullable
    protected View mListLoading;
    @Nullable
    protected LinearLayout mReuseNoConn;
    @Nullable
    protected LinearLayout mReuseDataException;
    @Nullable
    protected LinearLayout mReuseNoData;

    protected VM mListViewModel;

    protected LinearLayoutManager mLayoutManager;

    @Nullable
    protected SkeletonScreen mSkeletonScreen;

    protected RecyclerView.ItemDecoration mItemDecoration;

    private int[] lastPositions;
    private int lastVisibleItemPosition;

    protected abstract ListAdapter provideListAdapter();

    protected RecyclerView.ItemDecoration getItemDecoration() {
        mItemDecoration = new VerticalItemDecoration(getContext(), 8, true);
        return mItemDecoration;
    }

    protected VM provideListViewModel() {
        Class<VM> viewModelClass = getViewModelClass();
        if (!NormalListViewModel.class.isAssignableFrom(viewModelClass)) {
            return ViewModelProviders.of(this).get(viewModelClass);
        } else {
            NormalListViewModel.Factory factory = new NormalListViewModel.Factory(HaloApp.getInstance(), this);
            return ViewModelProviders.of(this, factory).get(viewModelClass);
        }
    }

    @Override
    protected int getLayoutId() {
        return R.layout.fragment_list_base;
    }

    /**
     * 是否自动加载
     */
    protected boolean isAutomaticLoad() {
        return true;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mListRv = mCachedView.findViewById(R.id.list_rv);
        mListRefresh = mCachedView.findViewById(R.id.list_refresh);
        mListLoading = mCachedView.findViewById(R.id.reuse_ll_loading);
        mReuseNoConn = mCachedView.findViewById(R.id.reuse_no_connection);
        mReuseNoData = mCachedView.findViewById(R.id.reuse_none_data);
        mReuseDataException = mCachedView.findViewById(R.id.reuse_data_exception);

        mListViewModel = provideListViewModel();
        mListViewModel.mEntrance = mEntrance;
        mListViewModel.getObsListData().observe(this, this);
        mListViewModel.getLoadStatusLiveData().observe(this, o -> {
            if (o instanceof LoadStatus) {
                LoadStatus loadStatus = (LoadStatus) o;
                switch (loadStatus) {
                    case INIT_EMPTY:
                        onLoadEmpty();
                        break;
                    case INIT_FAILED:
                        onLoadError();
                        break;
                    case INIT_EXCEPTION:
                        onLoadNotFound();
                        break;
                    case INIT_LOADED:
                        onLoadDone();
                        break;
                    case INIT_OVER:
                        onLoadDone();
                    case INIT:
                    case LIST_OVER:
                    case LIST_LOADED:
                    case LIST_FAILED:
                    case LIST_LOADING:
                        provideListAdapter().loadChange(loadStatus);
                        break;
                }
            }
        });

        if (isAutomaticLoad()) mListViewModel.load(LoadType.NORMAL);

        RecyclerView.ItemDecoration itemDecoration = getItemDecoration();
        if (itemDecoration != null) mListRv.addItemDecoration(itemDecoration);
    }

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

        if (mListRefresh != null) {
            mListRefresh.setColorSchemeResources(R.color.primary_theme);
            mListRefresh.setOnRefreshListener(this);
        }
        mLayoutManager = new FixLinearLayoutManager(getContext());
        ((DefaultItemAnimator) mListRv.getItemAnimator()).setSupportsChangeAnimations(false);
        mListRv.setLayoutManager(mLayoutManager);
        mListRv.setAdapter(provideListAdapter());
        mListRv.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                if (!shouldLoadMore()) return;
                RecyclerView.LayoutManager layoutManager = mListRv.getLayoutManager();
                if (layoutManager instanceof LinearLayoutManager) {
                    if (((LinearLayoutManager) layoutManager).findLastVisibleItemPosition() == provideListAdapter().getItemCount() - 1
                            && RecyclerView.SCROLL_STATE_IDLE == newState) {
                        mListViewModel.load(LoadType.NORMAL);
                    }
                } else if (layoutManager instanceof StaggeredGridLayoutManager) {
                    int visibleItemCount = layoutManager.getChildCount();
                    int totalItemCount = layoutManager.getItemCount();
                    if ((visibleItemCount > 0 && newState == RecyclerView.SCROLL_STATE_IDLE && (lastVisibleItemPosition) >= totalItemCount - 1)) {
                        mListViewModel.load(LoadType.NORMAL);
                    }
                }
            }

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

                RecyclerView.LayoutManager layoutManager = mListRv.getLayoutManager();
                if (layoutManager instanceof StaggeredGridLayoutManager) {
                    if (lastPositions == null) {
                        lastPositions = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
                    }
                    ((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(lastPositions);
                    lastVisibleItemPosition = NumberUtils.findMax(lastPositions);
                }
            }
        });
        if (mReuseNoConn != null) mReuseNoConn.setOnClickListener(view1 -> onLoadRefresh());
    }

    private Class<VM> getViewModelClass() {
        Type t = getClass().getGenericSuperclass();
        Type[] params = ((ParameterizedType) t).getActualTypeArguments();
        return (Class<VM>) params[1]; // 该类泛型类型中第二个是<VM>
    }

    @Override
    public void onRefresh() {
        onLoadRefresh();
    }

    @Override
    public void onChanged(@Nullable List<T> ts) {
        if (ts != null) {
            provideListAdapter().setListData(ts);
        }
    }

    @Override
    public Observable<List<T>> provideDataObservable(int page) {
        return null;
    }

    @Override
    public Single<List<T>> provideDataSingle(int page) {
        return null;
    }

    public void onLoadRefresh() {
        showSkeleton(true);
        if (mReuseNoConn != null) mReuseNoConn.setVisibility(View.GONE);
        if (mListLoading != null)
            mListLoading.setVisibility(mListRefresh == null || !mListRefresh.isRefreshing() ? View.VISIBLE : View.GONE);
        if (mReuseNoData != null) mReuseNoData.setVisibility(View.GONE);
        if (mReuseDataException != null) mReuseDataException.setVisibility(View.GONE);
        mListRv.setVisibility(View.GONE);
        mBaseHandler.postDelayed(() -> {
            mListViewModel.load(LoadType.REFRESH);
        }, 500);
    }

    public void onLoadDone() {
        showSkeleton(false);
        if (mReuseNoConn != null) mReuseNoConn.setVisibility(View.GONE);
        if (mReuseNoData != null) mReuseNoData.setVisibility(View.GONE);
        if (mListLoading != null) mListLoading.setVisibility(View.GONE);
        if (mReuseDataException != null) mReuseDataException.setVisibility(View.GONE);
        mListRv.setVisibility(View.VISIBLE);
        hideRefreshingLayout();

        mListRv.postDelayed(() -> {
            if (provideListAdapter().mEntityList.size() < theNumberNeededToFillAScreen()) {
                autoLoadMore();
            }
        }, getAutoLoadMoreDelay());
    }

    public void onLoadError() {
        showSkeleton(false);
        if (mReuseNoConn != null) mReuseNoConn.setVisibility(View.VISIBLE);
        if (mReuseNoData != null) mReuseNoData.setVisibility(View.GONE);
        if (mListLoading != null) mListLoading.setVisibility(View.GONE);
        if (mReuseDataException != null) mReuseDataException.setVisibility(View.GONE);
        mListRv.setVisibility(View.GONE);
        hideRefreshingLayout();
    }

    public void onLoadNotFound() {
        showSkeleton(false);
        if (mReuseDataException != null) mReuseDataException.setVisibility(View.VISIBLE);
        if (mReuseNoData != null) mReuseNoData.setVisibility(View.GONE);
        if (mListLoading != null) mListLoading.setVisibility(View.GONE);
        if (mReuseNoConn != null) mReuseNoConn.setVisibility(View.GONE);
        mListRv.setVisibility(View.GONE);
        hideRefreshingLayout();
    }

    public void onLoadEmpty() {
        showSkeleton(false);
        if (mReuseNoConn != null) mReuseNoConn.setVisibility(View.GONE);
        if (mReuseNoData != null) mReuseNoData.setVisibility(View.VISIBLE);
        if (mListLoading != null) mListLoading.setVisibility(View.GONE);
        if (mReuseDataException != null) mReuseDataException.setVisibility(View.GONE);
        mListRv.setVisibility(View.GONE);
        hideRefreshingLayout();
    }

    protected void showSkeleton(boolean showSkeleton) {
        if (mSkeletonScreen != null) {
            if (showSkeleton) {
                mSkeletonScreen.show();
            } else {
                mSkeletonScreen.hide();
            }
        }
    }

    // 需要自动加载更多的页面重载这个方法 (默认空方法)
    protected void autoLoadMore() {

    }

    // 执行自动加载更多的延时
    protected int getAutoLoadMoreDelay() {
        return 500;
    }

    // 填充一个页面所需的 Item 数量 (自己估算)
    protected int theNumberNeededToFillAScreen() {
        return 4;
    }

    protected void hideRefreshingLayout() {
        if (mListRefresh != null) mListRefresh.setRefreshing(false);
    }

    protected boolean shouldLoadMore() {
        return true;
    }

    @Override
    protected void onDarkModeChanged() {
        super.onDarkModeChanged();
        mCachedView.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.ui_background));
        if (provideListAdapter() != null) {
            ExtensionsKt.tryToClearRecycler(mListRv);
            mListRv.getRecycledViewPool().clear();
            provideListAdapter().notifyItemRangeChanged(0, provideListAdapter().getItemCount());
            if (mItemDecoration != null) {
                mListRv.removeItemDecoration(mItemDecoration);
                mListRv.addItemDecoration(getItemDecoration());
            }
        }
    }
}
