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.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.gh.gamecenter.common.R;
import com.gh.gamecenter.common.base.activity.ToolBarActivity;
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.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

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

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

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

    protected VM mListViewModel;

    protected LinearLayoutManager mLayoutManager;

    protected abstract ListAdapter provideListAdapter();

    private int[] lastPositions;
    private int lastVisibleItemPosition;

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

    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);
        }
    }

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

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mListRv = findViewById(R.id.list_rv);
        mListRefresh = findViewById(R.id.list_refresh);
        mListLoading = findViewById(R.id.reuse_ll_loading);
        mReuseNoConn = findViewById(R.id.reuse_no_connection);
        mReuseNoData = findViewById(R.id.reuse_none_data);
        mReuseDataException = findViewById(R.id.reuse_data_exception);

        // init ViewModel
        mListViewModel = provideListViewModel();
        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);

        // init View
        RecyclerView.ItemDecoration itemDecoration = getItemDecoration();
        if (itemDecoration != null) {
            mListRv.addItemDecoration(itemDecoration);
        }
        if (mListRefresh != null) {
            mListRefresh.setColorSchemeResources(R.color.theme);
            mListRefresh.setOnRefreshListener(this);
        }
        mLayoutManager = new FixLinearLayoutManager(this);
        ((DefaultItemAnimator) mListRv.getItemAnimator()).setSupportsChangeAnimations(false);
        mListRv.setLayoutManager(mLayoutManager);
        mListRv.setAdapter(provideListAdapter());
        mListRv.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                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);
                }
            }
        });
        mReuseNoConn.setOnClickListener(view1 -> onLoadRefresh());
    }

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

    @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() {
        mReuseNoConn.setVisibility(View.GONE);
        mReuseNoData.setVisibility(View.GONE);
        mListLoading.setVisibility(mListRefresh == null || !mListRefresh.isRefreshing() ? View.VISIBLE : View.GONE);
        mReuseDataException.setVisibility(View.GONE);
        mListRv.setVisibility(View.GONE);
        mBaseHandler.postDelayed(() -> {
            mListViewModel.load(LoadType.REFRESH);
        }, 500);
    }

    public void onLoadDone() {
        mReuseNoConn.setVisibility(View.GONE);
        mReuseNoData.setVisibility(View.GONE);
        mListLoading.setVisibility(View.GONE);
        mReuseDataException.setVisibility(View.GONE);
        mListRv.setVisibility(View.VISIBLE);
        mListRefresh.setRefreshing(false);
    }

    public void onLoadError() {
        mReuseNoConn.setVisibility(View.VISIBLE);
        mReuseNoData.setVisibility(View.GONE);
        mListLoading.setVisibility(View.GONE);
        mReuseDataException.setVisibility(View.GONE);
        mListRv.setVisibility(View.GONE);
        mListRefresh.setRefreshing(false);
    }

    public void onLoadNotFound() {
        mReuseNoData.setVisibility(View.GONE);
        mListLoading.setVisibility(View.GONE);
        mReuseNoConn.setVisibility(View.GONE);
        mReuseDataException.setVisibility(View.VISIBLE);
        mListRv.setVisibility(View.GONE);
        mListRefresh.setRefreshing(false);
    }

    public void onLoadEmpty() {
        mReuseNoConn.setVisibility(View.GONE);
        mReuseNoData.setVisibility(View.VISIBLE);
        mListLoading.setVisibility(View.GONE);
        mReuseDataException.setVisibility(View.GONE);
        mListRv.setVisibility(View.GONE);
        mListRefresh.setRefreshing(false);
    }

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