package com.yl.recyclerview.wrapper;

import android.content.Context;
import android.os.Vibrator;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;

import com.yl.recyclerview.helper.ItemMoveCallback;
import com.yl.recyclerview.listener.OnCustomClickListener;
import com.yl.recyclerview.listener.OnItemClickListener;

import java.util.Collections;
import java.util.List;

/**
 * An adapter can make {@link RecyclerView} basic drag & drop.
 * <p>
 * Created by yangle on 2017/11/17.
 * Website:http://www.yangle.tech
 */
public class DragAndDropWrapper extends RecyclerView.Adapter<RecyclerView.ViewHolder>
        implements ItemMoveCallback.ItemMoveListener {

    // Origin adapter
    private RecyclerView.Adapter<RecyclerView.ViewHolder> mAdapter;
    // Data list
    private List<?> mDataList;
    // ItemTouchHelper
    private ItemTouchHelper mItemTouchHelper;
    // Default long click delay 200ms.
    private long mDelay = 200;
    // Long click response vibrate, default is false.
    private boolean mIsVibrate;
    // Item click listener.
    private OnItemClickListener mItemClickListener;

    public DragAndDropWrapper(RecyclerView.Adapter<RecyclerView.ViewHolder> adapter, List<?> dataList) {
        this.mAdapter = adapter;
        this.mDataList = dataList;
    }

    public DragAndDropWrapper(RecyclerView.Adapter<RecyclerView.ViewHolder> adapter, List<?> dataList,
                              long delay) {
        this.mAdapter = adapter;
        this.mDataList = dataList;
        this.mDelay = delay;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return mAdapter.onCreateViewHolder(parent, viewType);
    }

    @Override
    public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) {
        mAdapter.onBindViewHolder(holder, position);

        // Custom delay long click listener.
        // The item root view must be clickable.
        holder.itemView.setOnTouchListener(new OnCustomClickListener(mDelay) {
            @Override
            public void onLongClickListener(View view) {
                if (mItemTouchHelper != null) {
                    vibrate(holder.itemView.getContext());
                    mItemTouchHelper.startDrag(holder);
                }
            }

            @Override
            public void onClickListener(View view) {
                if (mItemClickListener != null) {
                    mItemClickListener.onItemClick(view, position);
                }
            }
        });
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position,
                                 @NonNull List<Object> payloads) {
        if (payloads.isEmpty()) {
            onBindViewHolder(holder, position);
        } else {
            mAdapter.onBindViewHolder(holder, position, payloads);
        }
    }

    @Override
    public int getItemCount() {
        return mAdapter.getItemCount();
    }

    @Override
    public boolean onItemMove(final RecyclerView.ViewHolder viewHolder,
                              final RecyclerView.ViewHolder target,
                              final int fromPosition, final int toPosition) {
        if (fromPosition < toPosition) {
            for (int i = fromPosition; i < toPosition; i++) {
                Collections.swap(mDataList, i, i + 1);
            }
        } else {
            for (int i = fromPosition; i > toPosition; i--) {
                Collections.swap(mDataList, i, i - 1);
            }
        }
        notifyItemMoved(fromPosition, toPosition);

        // Swap click listener.
        viewHolder.itemView.setOnTouchListener(new OnCustomClickListener(mDelay) {
            @Override
            public void onLongClickListener(View view) {
                if (mItemTouchHelper != null) {
                    vibrate(viewHolder.itemView.getContext());
                    mItemTouchHelper.startDrag(viewHolder);
                }
            }

            @Override
            public void onClickListener(View view) {
                if (mItemClickListener != null) {
                    mItemClickListener.onItemClick(view, toPosition);
                }
            }
        });
        target.itemView.setOnTouchListener(new OnCustomClickListener(mDelay) {
            @Override
            public void onLongClickListener(View view) {
                if (mItemTouchHelper != null) {
                    vibrate(target.itemView.getContext());
                    mItemTouchHelper.startDrag(target);
                }
            }

            @Override
            public void onClickListener(View view) {
                if (mItemClickListener != null) {
                    mItemClickListener.onItemClick(view, fromPosition);
                }
            }
        });
        return true;
    }

    /**
     * Attach to RecyclerView for drag & drop.
     *
     * @param recyclerView RecyclerView
     */
    public void attachToRecyclerView(RecyclerView recyclerView) {
        attachToRecyclerView(recyclerView, false);
    }

    /**
     * Attach to RecyclerView for drag & drop.
     *
     * @param recyclerView RecyclerView
     * @param isFreedom    true: item can move up|down|left|right
     *                     false: item can move up|down
     */
    public void attachToRecyclerView(RecyclerView recyclerView, boolean isFreedom) {
        ItemTouchHelper.Callback callback = new ItemMoveCallback(this, isFreedom);
        mItemTouchHelper = new ItemTouchHelper(callback);
        mItemTouchHelper.attachToRecyclerView(recyclerView);
    }

    /**
     * Register a callback to be invoked when this view is clicked. If this view is not
     * clickable, it becomes clickable.
     *
     * @param onItemClickListener The callback that will run
     */
    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        this.mItemClickListener = onItemClickListener;
    }

    /**
     * Long click response vibrate, default is false.
     * Need permission: <uses-permission android:name="android.permission.VIBRATE" />
     *
     * @param isVibrate true: vibrate false: normal
     */
    public void setIsVibrate(boolean isVibrate) {
        this.mIsVibrate = isVibrate;
    }

    /**
     * Device vibrate
     *
     * @param context Context
     */
    private void vibrate(Context context) {
        if (!mIsVibrate) {
            return;
        }
        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
        if (vibrator != null) {
            vibrator.vibrate(200);
        }
    }
}