/*
 * @Copyright 2018-2026 HardBackNutter
 * @License GNU General Public License
 *
 * This file is part of NeverTooManyBooks.
 *
 * NeverTooManyBooks is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * NeverTooManyBooks is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with NeverTooManyBooks. If not, see <http://www.gnu.org/licenses/>.
 */
package com.hardbacknutter.nevertoomanybooks.widgets.adapters;

import android.view.LayoutInflater;
import android.view.ViewGroup;

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

import java.util.List;
import java.util.function.Function;

import com.hardbacknutter.nevertoomanybooks.databinding.RowChoiceSingleBinding;

/**
 * Add a list of RadioButtons to a RecyclerView.
 * <p>
 * Row layout: {@code R.layout.row_choice_single}
 *
 * @param <T> type of the item
 */
public class RadioGroupRecyclerAdapter<T>
        extends RecyclerView.Adapter<RadioGroupRecyclerAdapter.Holder> {

    @NonNull
    private final List<T> items;
    @NonNull
    private final Function<Integer, CharSequence> labelSupplier;
    @Nullable
    private final SelectionListener<T> selectionListener;
    /** The (pre-)selected item. */
    @Nullable
    private T selection;

    /**
     * Constructor.
     *
     * @param items         List of items
     * @param labelSupplier given the position in the list, supply a label for the item
     * @param selection     (optional) the pre-selected item
     * @param listener      (optional) when provided, the user selection will be sent
     *                      to this listener each time it changes;
     *                      Alternatively use {@link #getSelection()} when done.
     */
    public RadioGroupRecyclerAdapter(@NonNull final List<T> items,
                                     @NonNull final Function<Integer, CharSequence> labelSupplier,
                                     @Nullable final T selection,
                                     @Nullable final SelectionListener<T> listener) {

        this.items = items;
        this.labelSupplier = labelSupplier;
        this.selection = selection;
        selectionListener = listener;
    }

    @Override
    @NonNull
    public Holder onCreateViewHolder(@NonNull final ViewGroup parent,
                                     final int viewType) {
        final RowChoiceSingleBinding vb = RowChoiceSingleBinding.inflate(
                LayoutInflater.from(parent.getContext()), parent, false);
        final Holder holder = new Holder(vb);
        holder.vb.btnOption.setOnClickListener(v -> onItemCheckChanged(holder));
        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull final Holder holder,
                                 final int position) {
        final boolean checked = selection != null && selection.equals(items.get(position));
        holder.vb.btnOption.setChecked(checked);
        holder.vb.btnOption.setText(labelSupplier.apply(position));
    }

    private void onItemCheckChanged(@NonNull final Holder holder) {
        final int position = holder.getAbsoluteAdapterPosition();
        if (position == RecyclerView.NO_POSITION) {
            return;
        }

        final int oldPosition = items.indexOf(selection);
        selection = items.get(position);

        if (oldPosition != RecyclerView.NO_POSITION && oldPosition != position) {
            notifyItemChanged(oldPosition);
        }

        if (selectionListener != null) {
            // use a post allowing the UI to update the view first
            holder.vb.btnOption.post(() -> selectionListener.onSelected(selection));
        }
    }

    /**
     * Get the selected item.
     *
     * @return item selected, can be {@code null} if none selected.
     */
    @Nullable
    public T getSelection() {
        return selection;
    }

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

    @FunctionalInterface
    public interface SelectionListener<T> {

        /**
         * Called after the user selected an item.
         *
         * @param item selected, can be {@code null} if none selected.
         */
        void onSelected(@Nullable T item);
    }

    /**
     * Row ViewHolder for {@link RadioGroupRecyclerAdapter}.
     */
    public static class Holder
            extends RecyclerView.ViewHolder {

        @NonNull
        private final RowChoiceSingleBinding vb;

        Holder(@NonNull final RowChoiceSingleBinding vb) {
            super(vb.getRoot());
            this.vb = vb;
        }
    }
}
