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

import android.app.DatePickerDialog;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.ArrayAdapter;
import android.widget.MultiAutoCompleteTextView;

import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;

import com.annimon.stream.Stream;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Objects;

import it.integry.integrywmsnative.R;
import it.integry.integrywmsnative.core.class_router.ClassRouter;
import it.integry.integrywmsnative.core.class_router.interfaces.IFiltroOrdiniVendita;
import it.integry.integrywmsnative.core.di.BindableString;
import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.utility.UtilityDate;
import it.integry.integrywmsnative.databinding.DialogVenditaFiltroAvanzatoBinding;
import it.integry.integrywmsnative.gest.ordini_uscita_elenco.OrdiniUscitaElencoDTO;


public class DialogVenditaFiltroAvanzatoView {


    private final AlertDialog currentAlert;
    private final Context currentContext;

    private final RunnableArgs<DialogVenditaFiltroAvanzatoViewModel> currentOnFilterDone;



    public BindableString deposito = new BindableString();
    public BindableString idViaggio = new BindableString();
    public BindableString numOrds = new BindableString();
    public BindableString cliente = new BindableString();
    public BindableString dataConsegna = new BindableString();
    public BindableString terminiConsegna = new BindableString();
    public BindableString agente = new BindableString();
    public BindableString vettore = new BindableString();
    public BindableString automezzo = new BindableString();
    public BindableString paese = new BindableString();

    public Date dataConsegnaDate;

    private ArrayAdapter<String> arrayAdapterCodMdep;
    private ArrayAdapter<String> arrayAdapterIdViaggio;
    private ArrayAdapter<String> arrayAdapterNumOrds;
    private ArrayAdapter<String> arrayAdapterCliente;
    private ArrayAdapter<String> arrayAdapterTermCons;
    private ArrayAdapter<String> arrayAdapterVettore;
    private ArrayAdapter<String> arrayAdapterAgente;
    private ArrayAdapter<String> arrayAdapterAutomezzo;
    private ArrayAdapter<String> arrayAdapterPaese;

    private final DialogVenditaFiltroAvanzatoViewModel viewModel;

    public static AlertDialog make(final Context context,
                                   final List<OrdiniUscitaElencoDTO> ordersList,
                                   DialogVenditaFiltroAvanzatoViewModel baseViewModel,
                                   RunnableArgs<DialogVenditaFiltroAvanzatoViewModel> onDismiss) {
        return new DialogVenditaFiltroAvanzatoView(context, ordersList, baseViewModel, onDismiss).currentAlert;
    }

    private DialogVenditaFiltroAvanzatoView(final Context context, final List<OrdiniUscitaElencoDTO> ordersList, DialogVenditaFiltroAvanzatoViewModel baseViewModel, RunnableArgs<DialogVenditaFiltroAvanzatoViewModel> onDismiss) {
        currentContext = context;
        currentOnFilterDone = onDismiss;

        viewModel = baseViewModel != null ? baseViewModel : new DialogVenditaFiltroAvanzatoViewModel();
        viewModel.init(ordersList);

        LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );

        DialogVenditaFiltroAvanzatoBinding binding = DataBindingUtil.inflate(inflater, R.layout.dialog_vendita_filtro_avanzato, null, false);

        final AlertDialog.Builder alertDialog = new AlertDialog.Builder(context)
                .setView(binding.getRoot());

        binding.setView(this);
        binding.setViewmodel(viewModel);
        initViewModel(viewModel);
        initView(binding);

        currentAlert = alertDialog.create();
        currentAlert.setCanceledOnTouchOutside(false);

        currentAlert.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        currentAlert.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

        binding.positiveBtn.setOnClickListener(view -> {
            currentAlert.dismiss();
        });

        binding.neutralBtn.setOnClickListener(view -> {
            resetAll();
        });


        currentAlert.setOnDismissListener(dialogInterface -> {
            if(currentOnFilterDone != null) currentOnFilterDone.run(viewModel);
        });

    }

    private void initView(DialogVenditaFiltroAvanzatoBinding bindings) {
        IFiltroOrdiniVendita filtroOrdiniVendita = ClassRouter.getInstance(ClassRouter.PATH.FILTRO_ORDINI_VENDITA);

//        bindings.filledExposedDropdownDataCons.setOnFocusChangeListener((v, hasFocus) -> {
//            bindings.filledExposedDropdownDataCons.callOnClick();
//        });

        bindings.filledExposedDropdownDataCons.setOnClickListener(view -> {
            Calendar c = UtilityDate.getCalendarInstance();

            if(dataConsegnaDate != null) {
                c.setTime(dataConsegnaDate);
            }

            int mYear = c.get(Calendar.YEAR);
            int mMonth = c.get(Calendar.MONTH);
            int mDay = c.get(Calendar.DAY_OF_MONTH);

            DatePickerDialog datePickerDialog = new DatePickerDialog(currentContext,
                    (view2, year, month, day) -> {

                        dataConsegnaDate = new GregorianCalendar(year, month, day).getTime();
                        dataConsegna.set(UtilityDate.formatDate(dataConsegnaDate, UtilityDate.COMMONS_DATE_FORMATS.DMY_HUMAN));

                    }, mYear, mMonth, mDay);
            datePickerDialog.show();
        });


        arrayAdapterCodMdep = new ArrayAdapter(currentContext, R.layout.dialog_vendita_filtro_avanzato__single_item);
        arrayAdapterCodMdep.addAll(getAvailableCodMdeps(false));
        bindings.inputCodMdepNew.setVisibility(filtroOrdiniVendita.shoudShowCodMdepFilter() ? View.VISIBLE : View.GONE);
        bindings.filledExposedDropdownCodMdep.setAdapter(arrayAdapterCodMdep);

        arrayAdapterIdViaggio = new ArrayAdapter(currentContext, R.layout.dialog_vendita_filtro_avanzato__single_item);
        arrayAdapterIdViaggio.addAll(getAvailableIdViaggio(false));
        bindings.inputIdViaggio.setVisibility(filtroOrdiniVendita.shoudShowIdViaggioFilter() ? View.VISIBLE : View.GONE);
        bindings.filledExposedDropdownIdViaggio.setAdapter(arrayAdapterIdViaggio);

        arrayAdapterAgente = new ArrayAdapter(currentContext, R.layout.dialog_vendita_filtro_avanzato__single_item);
        arrayAdapterAgente.addAll(getAvailableAgente(false));
        bindings.inputAgente.setVisibility(filtroOrdiniVendita.shoudShowAgenteFilter() ? View.VISIBLE : View.GONE);
        bindings.filledExposedDropdownAgente.setAdapter(arrayAdapterAgente);

        arrayAdapterNumOrds = new ArrayAdapter(currentContext, R.layout.dialog_vendita_filtro_avanzato__single_item);
        arrayAdapterNumOrds.addAll(getAvailableNumOrds(false));
        bindings.filledExposedDropdownNumOrds.setAdapter(arrayAdapterNumOrds);
        bindings.filledExposedDropdownNumOrds.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());

        arrayAdapterCliente = new ArrayAdapter(currentContext, R.layout.dialog_vendita_filtro_avanzato__single_item);
        arrayAdapterCliente.addAll(getAvailableCliente(false));
        bindings.filledExposedDropdownCliente.setAdapter(arrayAdapterCliente);

        arrayAdapterTermCons = new ArrayAdapter(currentContext, R.layout.dialog_vendita_filtro_avanzato__single_item);
        arrayAdapterTermCons.addAll(getAvailableTermCons(false));
        bindings.filledExposedDropdownTermCons.setAdapter(arrayAdapterTermCons);

        arrayAdapterVettore = new ArrayAdapter(currentContext, R.layout.dialog_vendita_filtro_avanzato__single_item);
        arrayAdapterVettore.addAll(getAvailableVettori(false));
        bindings.filledExposedDropdownVettore.setAdapter(arrayAdapterVettore);

        arrayAdapterAutomezzo = new ArrayAdapter(currentContext, R.layout.dialog_vendita_filtro_avanzato__single_item);
        arrayAdapterAutomezzo.addAll(getAvailableAutomezzi(false));
        bindings.filledExposedDropdownAutomezzo.setAdapter(arrayAdapterAutomezzo);

        arrayAdapterPaese = new ArrayAdapter(currentContext, R.layout.dialog_vendita_filtro_avanzato__single_item);
        arrayAdapterPaese.addAll(getAvailablePaesi(false));
        bindings.filledExposedDropdownPaese.setAdapter(arrayAdapterPaese);


        refreshAll();
    }

    private void initViewModel(DialogVenditaFiltroAvanzatoViewModel viewModel) {
        viewModel.applyAllTests();

        BindableString.registerListener(idViaggio, value -> {
            viewModel.setIDViaggioFilter(value);
            viewModel.applyAllTests();

            refreshArrayAdapter(arrayAdapterCodMdep, getAvailableCodMdeps(true));
            refreshArrayAdapter(arrayAdapterNumOrds, getAvailableNumOrds(true));
            refreshArrayAdapter(arrayAdapterCliente, getAvailableCliente(true));
            refreshArrayAdapter(arrayAdapterTermCons, getAvailableTermCons(true));
            refreshArrayAdapter(arrayAdapterVettore, getAvailableVettori(true));
            refreshArrayAdapter(arrayAdapterAutomezzo, getAvailableAutomezzi(true));
            refreshArrayAdapter(arrayAdapterAgente, getAvailableAgente(true));
            refreshArrayAdapter(arrayAdapterPaese, getAvailablePaesi(true));
        });

        BindableString.registerListener(deposito, value -> {
            viewModel.setDepositoFilter(value);
            viewModel.applyAllTests();

            refreshArrayAdapter(arrayAdapterNumOrds, getAvailableNumOrds(true));
            refreshArrayAdapter(arrayAdapterIdViaggio, getAvailableIdViaggio(true));
            refreshArrayAdapter(arrayAdapterCliente, getAvailableCliente(true));
            refreshArrayAdapter(arrayAdapterTermCons, getAvailableTermCons(true));
            refreshArrayAdapter(arrayAdapterVettore, getAvailableVettori(true));
            refreshArrayAdapter(arrayAdapterAutomezzo, getAvailableAutomezzi(true));
            refreshArrayAdapter(arrayAdapterAgente, getAvailableAgente(true));
            refreshArrayAdapter(arrayAdapterPaese, getAvailablePaesi(true));
        });

        BindableString.registerListener(numOrds, value -> {
            viewModel.setNumOrdFilter(value);
            viewModel.applyAllTests();

            refreshArrayAdapter(arrayAdapterCodMdep, getAvailableCodMdeps(true));
            refreshArrayAdapter(arrayAdapterIdViaggio, getAvailableIdViaggio(true));
            refreshArrayAdapter(arrayAdapterCliente, getAvailableCliente(true));
            refreshArrayAdapter(arrayAdapterTermCons, getAvailableTermCons(true));
            refreshArrayAdapter(arrayAdapterVettore, getAvailableVettori(true));
            refreshArrayAdapter(arrayAdapterAutomezzo, getAvailableAutomezzi(true));
            refreshArrayAdapter(arrayAdapterAgente, getAvailableAgente(true));
            refreshArrayAdapter(arrayAdapterPaese, getAvailablePaesi(true));
        });

        BindableString.registerListener(cliente, value -> {
            viewModel.setClienteFilter(value);
            viewModel.applyAllTests();

            refreshArrayAdapter(arrayAdapterCodMdep, getAvailableCodMdeps(true));
            refreshArrayAdapter(arrayAdapterIdViaggio, getAvailableIdViaggio(true));
            refreshArrayAdapter(arrayAdapterNumOrds, getAvailableNumOrds(true));
            refreshArrayAdapter(arrayAdapterTermCons, getAvailableTermCons(true));
            refreshArrayAdapter(arrayAdapterVettore, getAvailableVettori(true));
            refreshArrayAdapter(arrayAdapterAutomezzo, getAvailableAutomezzi(true));
            refreshArrayAdapter(arrayAdapterAgente, getAvailableAgente(true));
            refreshArrayAdapter(arrayAdapterPaese, getAvailablePaesi(true));
        });

        BindableString.registerListener(terminiConsegna, value -> {
            viewModel.setTerminiConsegnaFilter(value);
            viewModel.applyAllTests();

            refreshArrayAdapter(arrayAdapterCodMdep, getAvailableCodMdeps(true));
            refreshArrayAdapter(arrayAdapterIdViaggio, getAvailableIdViaggio(true));
            refreshArrayAdapter(arrayAdapterNumOrds, getAvailableNumOrds(true));
            refreshArrayAdapter(arrayAdapterCliente, getAvailableCliente(true));
            refreshArrayAdapter(arrayAdapterVettore, getAvailableVettori(true));
            refreshArrayAdapter(arrayAdapterAutomezzo, getAvailableAutomezzi(true));
            refreshArrayAdapter(arrayAdapterAgente, getAvailableAgente(true));
            refreshArrayAdapter(arrayAdapterPaese, getAvailablePaesi(true));
        });

        BindableString.registerListener(vettore, value -> {
            viewModel.setVettoreFilter(value);
            viewModel.applyAllTests();

            refreshArrayAdapter(arrayAdapterCodMdep, getAvailableCodMdeps(true));
            refreshArrayAdapter(arrayAdapterIdViaggio, getAvailableIdViaggio(true));
            refreshArrayAdapter(arrayAdapterNumOrds, getAvailableNumOrds(true));
            refreshArrayAdapter(arrayAdapterCliente, getAvailableCliente(true));
            refreshArrayAdapter(arrayAdapterTermCons, getAvailableTermCons(true));
            refreshArrayAdapter(arrayAdapterAutomezzo, getAvailableAutomezzi(true));
            refreshArrayAdapter(arrayAdapterAgente, getAvailableAgente(true));
            refreshArrayAdapter(arrayAdapterPaese, getAvailablePaesi(true));
        });

        BindableString.registerListener(automezzo, value -> {
            viewModel.setAutomezzoFilter(value);
            viewModel.applyAllTests();

            refreshArrayAdapter(arrayAdapterCodMdep, getAvailableCodMdeps(true));
            refreshArrayAdapter(arrayAdapterIdViaggio, getAvailableIdViaggio(true));
            refreshArrayAdapter(arrayAdapterNumOrds, getAvailableNumOrds(true));
            refreshArrayAdapter(arrayAdapterCliente, getAvailableCliente(true));
            refreshArrayAdapter(arrayAdapterTermCons, getAvailableTermCons(true));
            refreshArrayAdapter(arrayAdapterVettore, getAvailableVettori(true));
            refreshArrayAdapter(arrayAdapterAgente, getAvailableAgente(true));
            refreshArrayAdapter(arrayAdapterPaese, getAvailablePaesi(true));
        });

        BindableString.resetListeners(dataConsegna);
        BindableString.registerListener(dataConsegna, value -> {
            viewModel.setDataConsegnaFilter(dataConsegnaDate);
            viewModel.applyAllTests();

            refreshArrayAdapter(arrayAdapterCodMdep, getAvailableCodMdeps(true));
            refreshArrayAdapter(arrayAdapterIdViaggio, getAvailableIdViaggio(true));
            refreshArrayAdapter(arrayAdapterNumOrds, getAvailableNumOrds(true));
            refreshArrayAdapter(arrayAdapterCliente, getAvailableCliente(true));
            refreshArrayAdapter(arrayAdapterTermCons, getAvailableTermCons(true));
            refreshArrayAdapter(arrayAdapterVettore, getAvailableVettori(true));
            refreshArrayAdapter(arrayAdapterAgente, getAvailableAgente(true));
            refreshArrayAdapter(arrayAdapterPaese, getAvailablePaesi(true));
            refreshArrayAdapter(arrayAdapterAutomezzo, getAvailableAutomezzi(true));
        });

        BindableString.resetListeners(agente);
        BindableString.registerListener(agente, value -> {
            viewModel.setAgenteFilter(value);
            viewModel.applyAllTests();

            refreshArrayAdapter(arrayAdapterCodMdep, getAvailableCodMdeps(true));
            refreshArrayAdapter(arrayAdapterIdViaggio, getAvailableIdViaggio(true));
            refreshArrayAdapter(arrayAdapterNumOrds, getAvailableNumOrds(true));
            refreshArrayAdapter(arrayAdapterCliente, getAvailableCliente(true));
            refreshArrayAdapter(arrayAdapterTermCons, getAvailableTermCons(true));
            refreshArrayAdapter(arrayAdapterVettore, getAvailableVettori(true));
            refreshArrayAdapter(arrayAdapterPaese, getAvailablePaesi(true));
            refreshArrayAdapter(arrayAdapterAutomezzo, getAvailableAutomezzi(true));
        });

        BindableString.resetListeners(paese);
        BindableString.registerListener(paese, value -> {
            viewModel.setPaeseFilter(value);
            viewModel.applyAllTests();

            refreshArrayAdapter(arrayAdapterCodMdep, getAvailableCodMdeps(true));
            refreshArrayAdapter(arrayAdapterIdViaggio, getAvailableIdViaggio(true));
            refreshArrayAdapter(arrayAdapterNumOrds, getAvailableNumOrds(true));
            refreshArrayAdapter(arrayAdapterCliente, getAvailableCliente(true));
            refreshArrayAdapter(arrayAdapterTermCons, getAvailableTermCons(true));
            refreshArrayAdapter(arrayAdapterVettore, getAvailableVettori(true));
            refreshArrayAdapter(arrayAdapterAgente, getAvailableAgente(true));
            refreshArrayAdapter(arrayAdapterAutomezzo, getAvailableAutomezzi(true));
        });

    }


    private void refreshArrayAdapter(ArrayAdapter<String> arrayAdapter, List<String> inputList) {
        arrayAdapter.clear();
        arrayAdapter.addAll(inputList);
        arrayAdapter.notifyDataSetChanged();
    }


    private List<String> getAvailableIdViaggio(boolean skipRecalc) {
        return Stream
                .of(Objects.requireNonNull(viewModel.getMutableFilteredOrderList().getValue()))
                .filter(x -> x.getIdViaggio() != null)
                .sortBy(x -> -x.getIdViaggio())
                .map(x -> x.getIdViaggio() != null ? x.getIdViaggio().toString() : null)
                .distinct()
                .toList();
    }

    private List<String> getAvailableAgente(boolean skipRecalc) {
        return Stream.of(Objects.requireNonNull(viewModel.getMutableFilteredOrderList().getValue()))
                .map(OrdiniUscitaElencoDTO::getNomeAgente)
                .distinct()
                .withoutNulls()
                .sorted()
                .toList();
    }

    private List<String> getAvailableCodMdeps(boolean skipRecalc) {
        return Stream.of(Objects.requireNonNull(viewModel.getMutableFilteredOrderList().getValue()))
                .map(OrdiniUscitaElencoDTO::getCodMdep)
                .distinct()
                .withoutNulls()
                .sorted()
                .toList();
    }

    private List<String> getAvailableCliente(boolean skipRecalc) {
        return Stream.of(Objects.requireNonNull(viewModel.getMutableFilteredOrderList().getValue()))
                .map(OrdiniUscitaElencoDTO::getRagSocOrd)
                .distinct()
                .withoutNulls()
                .sorted()
                .toList();
    }

    private List<String> getAvailableNumOrds(boolean skipRecalc) {
        return Stream.of(Objects.requireNonNull(viewModel.getMutableFilteredOrderList().getValue()))
                .map(x -> x.getNumOrd().toString())
                .distinct()
                .withoutNulls()
                .sorted()
                .toList();
    }

    private List<String> getAvailableTermCons(boolean skipRecalc) {
        return Stream.of(Objects.requireNonNull(viewModel.getMutableFilteredOrderList().getValue()))
                .map(OrdiniUscitaElencoDTO::getTermCons)
                .distinct()
                .withoutNulls()
                .sorted()
                .toList();
    }

    private List<String> getAvailableVettori(boolean skipRecalc) {
        return Stream.of(Objects.requireNonNull(viewModel.getMutableFilteredOrderList().getValue()))
                .filter(x -> x.getCodVvet() != null)
                .map(x -> x.getCodVvet() + " - " + x.getDescrizioneVettore())
                .distinct()
                .withoutNulls()
                .sorted()
                .toList();
    }

    private List<String> getAvailableAutomezzi(boolean skipRecalc) {
        return Stream.of(Objects.requireNonNull(viewModel.getMutableFilteredOrderList().getValue()))
                .map(OrdiniUscitaElencoDTO::getDescrizioneAuto)
                .distinct()
                .withoutNulls()
                .sorted()
                .toList();
    }

    private List<String> getAvailablePaesi(boolean skipRecalc) {
        return Stream.of(Objects.requireNonNull(viewModel.getMutableFilteredOrderList().getValue()))
                .map(OrdiniUscitaElencoDTO::getCitta)
                .withoutNulls()
                .distinct()
                .sorted()
                .toList();
    }


    public void refreshAll() {
        deposito.refresh();
        idViaggio.refresh();
        numOrds.refresh();
        cliente.refresh();
        terminiConsegna.refresh();
        vettore.refresh();
        automezzo.refresh();
        dataConsegna.refresh();
        agente.refresh();
        paese.refresh();
    }


    public void resetAll() {
        deposito.set(null);
        idViaggio.set(null);
        numOrds.set(null);
        cliente.set(null);
        dataConsegna.set(null);
        terminiConsegna.set(null);
        vettore.set(null);
        automezzo.set(null);
        agente.set(null);
        paese.set(null);
    }



}
