package it.integry.integrywmsnative.gest.ordini_uscita_elenco.filters;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.MutableLiveData;

import com.annimon.stream.ComparatorCompat;
import com.annimon.stream.Stream;
import com.ravikoradiya.liveadapter.LiveAdapter;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

import it.integry.integrywmsnative.BR;
import it.integry.integrywmsnative.R;
import it.integry.integrywmsnative.core.di.BindableBoolean;
import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.model.MtbGrup;
import it.integry.integrywmsnative.core.utility.UtilityBoolean;
import it.integry.integrywmsnative.databinding.LayoutFilterGruppoMercBinding;
import it.integry.integrywmsnative.ui.filter_chips.FilterLayoutView;

public class FilterGruppoMercLayoutView extends FilterLayoutView {

    protected LayoutFilterGruppoMercBinding mBindings;

    private List<MtbGrup> allGroupMerc;
    private List<MtbGrup> availableGroupMerc;
    private List<MtbGrup> preSelectedGroupMerc = new ArrayList<>();
    private List<MtbGrup> hiddenGroupMerc = new ArrayList<>();
    private final MutableLiveData<List<ListModel>> listModel = new MutableLiveData<>();

    private RunnableArgs<List<MtbGrup>> onFilterApplied;


    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        mBindings = DataBindingUtil.inflate(inflater, R.layout.layout_filter_gruppo_merc, container, false);
        this.mBindings.setView(this);

        refreshList();

        this.setSearchView(this.mBindings.searchView, newFilter -> {
            hiddenGroupMerc = Stream.of(allGroupMerc)
                    .filter(x -> !x.getCodMgrp().toUpperCase(Locale.ROOT).contains(newFilter.toUpperCase(Locale.ROOT)) &&
                            !x.getDescrizione().toUpperCase(Locale.ROOT).contains(newFilter.toUpperCase(Locale.ROOT)))
                    .toList();

            refreshList();
        });


        new LiveAdapter(listModel, getViewLifecycleOwner(), BR.item)
                .map(ListModel.class, R.layout.layout_filter_gruppo_merc__list_item)
                .into(this.mBindings.recyclerview);

        return mBindings.getRoot();
    }

    private void refreshList() {
        ComparatorCompat<ListModel> c =
                ComparatorCompat
                        .chain(new ComparatorCompat<ListModel>((x, y) -> UtilityBoolean.toInt(x.getSelected().get()) - UtilityBoolean.toInt(y.getSelected().get())))
                        .thenComparing(new ComparatorCompat<>((x, y) -> UtilityBoolean.toInt(x.getEnabled().get()) - UtilityBoolean.toInt(y.getEnabled().get())))
                        .thenComparing(new ComparatorCompat<>((x, y) -> y.getOriginalModel().getCodMgrp().compareTo(x.getOriginalModel().getCodMgrp())))
                        .reversed();

        listModel.setValue(Stream.of(getAllGroupMerc())
                .filter(x -> !hiddenGroupMerc.contains(x))
                .map(x -> {
                    var selectedBoolean = new BindableBoolean(preSelectedGroupMerc.contains(x));
                    selectedBoolean.addOnPropertyChangedCallback(() -> {
                        if (selectedBoolean.get()) preSelectedGroupMerc.add(x);
                        else preSelectedGroupMerc.remove(x);
                    });

                    return new ListModel()
                            .setSelected(new BindableBoolean(preSelectedGroupMerc.contains(x)))
                            .setEnabled(new BindableBoolean(availableGroupMerc.contains(x)))
                            .setOriginalModel(x);
                })
                .sorted(c)
                .toList());
    }


    public void onConfirm() {
        if (onFilterApplied == null) return;

        this.onFilterApplied.run(Stream.of(Objects.requireNonNull(listModel.getValue()))
                .filter(x -> x.selected.get())
                .map(x -> x.originalModel)
                .toList());

        dismiss();
    }

    public List<MtbGrup> getAllGroupMerc() {
        return allGroupMerc;
    }

    public FilterGruppoMercLayoutView setAllGroupMerc(List<MtbGrup> allGroupMerc) {
        this.allGroupMerc = allGroupMerc;
        return this;
    }

    public List<MtbGrup> getAvailableGroupMerc() {
        return availableGroupMerc;
    }

    public FilterGruppoMercLayoutView setAvailableGroupMerc(List<MtbGrup> availableGroupMerc) {
        this.availableGroupMerc = availableGroupMerc;
        return this;
    }

    public List<MtbGrup> getPreSelectedGroupMerc() {
        return preSelectedGroupMerc;
    }

    public FilterGruppoMercLayoutView setPreSelectedGroupMerc(List<MtbGrup> preSelectedGroupMerc) {
        this.preSelectedGroupMerc = preSelectedGroupMerc;
        return this;
    }

    public RunnableArgs<List<MtbGrup>> getOnFilterApplied() {
        return onFilterApplied;
    }

    public FilterGruppoMercLayoutView setOnFilterApplied(RunnableArgs<List<MtbGrup>> onFilterApplied) {
        this.onFilterApplied = onFilterApplied;
        return this;
    }

    public static class ListModel {
        private BindableBoolean selected = new BindableBoolean();
        private BindableBoolean enabled = new BindableBoolean();
        private MtbGrup originalModel;

        public BindableBoolean getSelected() {
            return selected;
        }

        public ListModel setSelected(BindableBoolean selected) {
            this.selected = selected;
            return this;
        }

        public BindableBoolean getEnabled() {
            return enabled;
        }

        public ListModel setEnabled(BindableBoolean enabled) {
            this.enabled = enabled;
            return this;
        }

        public MtbGrup getOriginalModel() {
            return originalModel;
        }

        public ListModel setOriginalModel(MtbGrup originalModel) {
            this.originalModel = originalModel;
            return this;
        }
    }
}
