/*
 * @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.bookdetails;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

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

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import com.hardbacknutter.fastscroller.OverlayProvider;
import com.hardbacknutter.nevertoomanybooks.R;
import com.hardbacknutter.nevertoomanybooks.booklist.style.Style;
import com.hardbacknutter.nevertoomanybooks.databinding.RowAuthorWorkBinding;
import com.hardbacknutter.nevertoomanybooks.dialogs.InfoPopup;
import com.hardbacknutter.nevertoomanybooks.entities.Author;
import com.hardbacknutter.nevertoomanybooks.entities.AuthorWork;
import com.hardbacknutter.nevertoomanybooks.entities.Details;
import com.hardbacknutter.nevertoomanybooks.fields.formatters.ClickableListFormatter;
import com.hardbacknutter.nevertoomanybooks.widgets.adapters.OnRowClickListener;
import com.hardbacknutter.nevertoomanybooks.widgets.adapters.RowViewHolder;
import com.hardbacknutter.nevertoomanybooks.widgets.popupmenu.ExtMenuButton;

public class AuthorWorksAdapter
        extends RecyclerView.Adapter<AuthorWorksAdapter.AuthorWorkHolder>
        implements OverlayProvider.PopupTextProvider {

    /** x/y offsets more or less arbitrary. */
    private static final int XOFF = 24;
    private static final int YOFF = -160;

    @NonNull
    private final List<? extends AuthorWork> works;
    @NonNull
    private final Style style;
    @NonNull
    private final List<Author> authors;
    @NonNull
    private final ClickableListFormatter<Author> authorFormatter;
    @Nullable
    private OnRowClickListener rowClickListener;
    @Nullable
    private OnRowClickListener rowShowMenuListener;
    @Nullable
    private ExtMenuButton contextMenuMode;

    /**
     * Constructor.
     *
     * @param context Current context
     * @param style   to use
     * @param authors the author who 'owns' the works list
     *                (passing in a list for ease of use / future use,
     *                but we only use the primary-author for now)
     * @param works   to show
     */
    public AuthorWorksAdapter(@NonNull final Context context,
                              @NonNull final Style style,
                              @NonNull final List<Author> authors,
                              @NonNull final List<? extends AuthorWork> works) {
        this.contextMenuMode = ExtMenuButton.getPreferredMode();
        this.style = style;
        this.authors = authors;
        this.works = works;

        authorFormatter = new ClickableListFormatter<>(context, (c, author) ->
                author.getLabel(c, Details.AutoSelect, style));
    }

    /**
     * Set the {@link OnRowClickListener} for a click on a row.
     *
     * @param listener to set
     */
    public void setOnRowClickListener(@Nullable final OnRowClickListener listener) {
        this.rowClickListener = listener;
    }

    /**
     * Set the {@link OnRowClickListener} for showing the context menu on a row.
     *
     * @param contextMenuMode how to show context menus
     * @param listener        to receive clicks
     */
    public void setOnRowShowMenuListener(@NonNull final ExtMenuButton contextMenuMode,
                                         @Nullable final OnRowClickListener listener) {
        this.rowShowMenuListener = listener;
        this.contextMenuMode = contextMenuMode;
    }

    @NonNull
    @Override
    public AuthorWorkHolder onCreateViewHolder(@NonNull final ViewGroup parent,
                                               final int viewType) {
        final AuthorWorkHolder holder;
        final RowAuthorWorkBinding vb = RowAuthorWorkBinding.inflate(
                LayoutInflater.from(parent.getContext()), parent, false);
        switch (AuthorWork.Type.getType((char) viewType)) {
            case TocEntry: {
                holder = new TocEntryHolder(vb, style, authorFormatter);
                break;
            }
            case BookLite:
            case Book: {
                holder = new BookHolder(vb, style, authorFormatter);
                break;
            }
            default:
                throw new IllegalArgumentException(String.valueOf(viewType));
        }

        holder.setOnRowClickListener(rowClickListener);
        holder.setOnRowLongClickListener(contextMenuMode, rowShowMenuListener);
        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull final AuthorWorkHolder holder,
                                 final int position) {

        final AuthorWork work = works.get(position);

        holder.onBind(work);

        // only display a primary author for this work if different from the main author
        boolean same = false;
        if (!authors.isEmpty()) {
            same = Objects.equals(work.getPrimaryAuthor(), authors.get(0));
        }
        holder.vb.author.setVisibility(same ? View.GONE : View.VISIBLE);
    }

    @Override
    public int getItemViewType(final int position) {
        final AuthorWork work = works.get(position);
        return work.getWorkType().asChar();
    }

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

    @NonNull
    @Override
    public String getPopupText(@NonNull final Context context,
                               final int position) {
        return works.get(position).getLabel(context, Details.AutoSelect, style);
    }

    @SuppressLint("UseCompatLoadingForDrawables")
    public static class TocEntryHolder
            extends AuthorWorkHolder {

        @NonNull
        private final String singleBookStr;
        @NonNull
        private final String multipleBooksStr;

        TocEntryHolder(@NonNull final RowAuthorWorkBinding vb,
                       @NonNull final Style style,
                       @NonNull final ClickableListFormatter<Author> authorFormatter) {
            super(vb, style, authorFormatter);

            final Resources res = itemView.getContext().getResources();
            // The entry is a story (etc...) which appears in one book only.
            singleBookStr = res.getString(R.string.lbl_table_of_content_entry);
            // The entry is a story (etc...) which appears in multiple books.
            multipleBooksStr = res.getString(R.string.tip_authors_works_multiple_books);

            vb.btnType.setIconResource(R.drawable.menu_book_24px);
        }

        @Override
        public void onBind(@NonNull final AuthorWork work) {
            super.onBind(work);
            if (work.getBookCount() > 1) {
                vb.btnType.setContentDescription(multipleBooksStr);
                vb.btnTypeBadge.setVisibility(View.VISIBLE);
                vb.btnTypeBadge.setText(String.valueOf(work.getBookCount()));
            } else {
                vb.btnType.setContentDescription(singleBookStr);
                vb.btnTypeBadge.setVisibility(View.GONE);
            }
        }
    }

    static class BookHolder
            extends AuthorWorkHolder {

        BookHolder(@NonNull final RowAuthorWorkBinding vb,
                   @NonNull final Style style,
                   @NonNull final ClickableListFormatter<Author> authorFormatter) {
            super(vb, style, authorFormatter);

            vb.btnType.setContentDescription(itemView.getContext().getString(R.string.lbl_book));
            vb.btnType.setIconResource(R.drawable.book_2_24px);
        }
    }

    public static class AuthorWorkHolder
            extends RowViewHolder {

        @NonNull
        final RowAuthorWorkBinding vb;
        @NonNull
        private final Style style;

        @NonNull
        private final ClickableListFormatter<Author> authorFormatter;

        AuthorWorkHolder(@NonNull final RowAuthorWorkBinding vb,
                         @NonNull final Style style,
                         @NonNull final ClickableListFormatter<Author> authorFormatter) {
            super(vb.getRoot());
            this.vb = vb;
            this.style = style;
            this.authorFormatter = authorFormatter;
        }

        @Override
        public void setOnRowClickListener(@Nullable final OnRowClickListener listener) {
            super.setOnRowClickListener(listener);

            if (listener != null) {
                vb.author.setOnClickListener(v -> listener
                        .onClick(v, getBindingAdapterPosition()));
            } else {
                vb.author.setOnClickListener(null);
            }
        }

        void onBind(@NonNull final AuthorWork work) {

            final Context context = itemView.getContext();
            vb.title.setText(work.getLabel(context, Details.AutoSelect, style));

            // screen space is at a premium here, and books can have 'yyyy-mm-dd' dates,
            // cut the date to just the year.
            final Optional<String> year = work.getFirstPublicationDate().getYear()
                                              .map(String::valueOf);
            if (year.isPresent()) {
                vb.year.setText(context.getString(R.string.brackets, year.get()));
                vb.year.setVisibility(View.VISIBLE);
            } else {
                vb.year.setVisibility(View.GONE);
            }

            final Author primaryAuthor = work.getPrimaryAuthor();
            vb.author.setText(primaryAuthor != null
                              ? authorFormatter.format(context, List.of(primaryAuthor))
                              : null);

            // not visible by default.
            vb.btnTypeBadge.setVisibility(View.GONE);

            vb.btnType.setOnClickListener(anchor -> {
                final String titles = work
                        .getBookTitles(context)
                        .stream()
                        .map(bt -> context
                                .getString(R.string.list_element,
                                           bt.getLabel(context, Details.AutoSelect, style)))
                        .collect(Collectors.joining("\n"));

                if (work.getBookCount() > 1) {
                    final String msg = context
                            .getString(R.string.info_story_in_multiple_books,
                                       work.getLabel(context, Details.AutoSelect, style),
                                       titles);
                    InfoPopup.show(anchor, XOFF, YOFF, msg);
                } else {
                    final String msg = context
                            .getString(R.string.info_story_in_single_book,
                                       work.getLabel(context, Details.AutoSelect, style),
                                       titles);
                    InfoPopup.show(anchor, XOFF, YOFF, msg);
                }
            });
        }
    }
}
