package it.integry.integrywmsnative.view.dialogs.ask_cliente.viewmodel;

import android.content.Context;
import android.widget.AutoCompleteTextView;
import android.widget.Toast;

import androidx.databinding.ObservableArrayList;
import androidx.databinding.ObservableList;
import androidx.databinding.ViewDataBinding;

import com.annimon.stream.Optional;
import com.annimon.stream.Stream;
import com.google.gson.reflect.TypeToken;
import com.tfb.fbtoast.FBToast;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import it.integry.barcode_base_android_library.model.BarcodeScanDTO;
import it.integry.integrywmsnative.R;
import it.integry.integrywmsnative.core.barcode_reader.BarcodeCallbackDTO;
import it.integry.integrywmsnative.core.barcode_reader.BarcodeManager;
import it.integry.integrywmsnative.core.expansion.OnListGeneralChangedCallback;
import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.rest.consumers.ISimpleOperationCallback;
import it.integry.integrywmsnative.core.rest.consumers.SystemRESTConsumer;
import it.integry.integrywmsnative.core.settings.SettingsManager;
import it.integry.integrywmsnative.core.utility.UtilityExceptions;
import it.integry.integrywmsnative.core.utility.UtilityHashMap;
import it.integry.integrywmsnative.databinding.DialogAskClientePage1Binding;
import it.integry.integrywmsnative.view.dialogs.ask_cliente.dto.DialogAskClienteClienteDTO;

public class DialogAskCliente_Page1ViewModel implements IDialogAskClienteViewModel {

    private Context mContext;
    private DialogAskClientePage1Binding mBinding;

    private int mBarcodeScannerInstanceID;

    private ArrayList<DialogAskClienteClienteDTO> availableClienti;
    private ObservableArrayList<String> codJcoms = new ObservableArrayList<>();

    public DialogAskCliente_Page1ViewModel() {

    }

    @Override
    public void setContext(Context context) {
        this.mContext = context;
    }

    @Override
    public void setBinding(ViewDataBinding binding) {
        this.mBinding = (DialogAskClientePage1Binding) binding;
    }

    @Override
    public void onShow() {

        String sql = "SELECT gtb_anag.cod_anag, rag_soc, jtb_comt.cod_jcom " +
                "FROM gtb_anag " +
                "LEFT OUTER JOIN jtb_comt ON gtb_anag.cod_anag = jtb_comt.cod_anag " +
                "INNER JOIN vtb_clie ON gtb_anag.cod_anag = vtb_clie.cod_anag " +
                "WHERE vtb_clie.flag_stato = 'A' " +
                "ORDER BY rag_soc";

        Type typeOfObjectsList = new TypeToken<ArrayList<HashMap<String, Object>>>() { }.getType();

        SystemRESTConsumer.processSqlStatic(sql, typeOfObjectsList, new ISimpleOperationCallback<ArrayList<HashMap<String, Object>>>() {
            @Override
            public void onSuccess(ArrayList<HashMap<String, Object>> value) {

                availableClienti = new ArrayList<>();

                Stream.of(value)
                        .groupBy(x -> x.get("codAnag").toString() + " " + x.get("ragSoc").toString())
                        .forEach(x -> {
                            DialogAskClienteClienteDTO dialogAskClienteClienteDTO = new DialogAskClienteClienteDTO();
                            dialogAskClienteClienteDTO.setCodAnag(UtilityHashMap.getValueIfExists(x.getValue().get(0), "codAnag"));
                            dialogAskClienteClienteDTO.setRagSoc(UtilityHashMap.getValueIfExists(x.getValue().get(0), "ragSoc"));

                            for (HashMap<String, Object> group : x.getValue()) {
                                if (group.containsKey("codJcom")) {
                                    dialogAskClienteClienteDTO.getCodJcoms().add(UtilityHashMap.getValueIfExists(group, "codJcom"));
                                }
                            }

                            availableClienti.add(dialogAskClienteClienteDTO);
                        });

                initializeAdapter(availableClienti);

                mBarcodeScannerInstanceID = BarcodeManager.addCallback(new BarcodeCallbackDTO()
                        .setOnScanSuccessfull(onScanSuccessful)
                        .setOnScanFailed(ex -> UtilityExceptions.defaultException(mContext, ex, false)));
                BarcodeManager.enable();
            }

            @Override
            public void onFailed(Exception ex) {

            }
        });

    }

    @Override
    public void onDismiss() {
        BarcodeManager.removeCallback(mBarcodeScannerInstanceID);
    }

    @Override
    public void setOnConfirmClickListener(Runnable onConfirm) {
        this.mBinding.buttonYes.setOnClickListener(v -> {
            if (validateCliente()) {
                this.resetClienteError();
                BarcodeManager.removeCallback(mBarcodeScannerInstanceID);
                if (onConfirm != null) onConfirm.run();
            } else {
                this.setClienteError(mContext.getResources().getText(R.string.not_valid_customer_error).toString());
            }

        });
    }


    private final RunnableArgs<BarcodeScanDTO> onScanSuccessful = data -> {
        BarcodeManager.disable();

        String barcode = data.getStringValue();

        DialogAskClienteClienteDTO resultCodAnag = searchBarcodeInCodAnag(barcode);

        if (resultCodAnag != null) {
            mBinding.dropdownCliente.setText(resultCodAnag.toString());
            refreshCodJcoms(resultCodAnag);
        } else {
            DialogAskClienteClienteDTO resultCodJcom = searchBarcodeInCodJcom(barcode);

            if(resultCodJcom != null) {
                mBinding.dropdownCliente.setText(resultCodJcom.toString());
                refreshCodJcoms(resultCodJcom);
                mBinding.dropdownCommessa.setText(barcode);
            } else {
                FBToast.errorToast(mContext, "Nessun risultato trovato", Toast.LENGTH_LONG);
                mBinding.dropdownCliente.setText("");
                mBinding.dropdownCommessa.setText("");
            }
        }

        BarcodeManager.enable();
    };


    private DialogAskClienteClienteDTO searchBarcodeInCodAnag(String barcode) {
        List<DialogAskClienteClienteDTO> resultCodAnag = Stream.of(availableClienti)
                .filter(x -> barcode.equalsIgnoreCase(x.getCodAnag()))
                .toList();
        if (resultCodAnag.size() > 0) {
            return resultCodAnag.get(0);
        } else return null;
    }

    private DialogAskClienteClienteDTO searchBarcodeInCodJcom(String barcode) {
        List<DialogAskClienteClienteDTO> resultCodJcom = Stream.of(availableClienti)
                .filter(x -> x.getCodJcoms().contains(barcode))
                .toList();
        if (resultCodJcom.size() > 0) {
            return resultCodJcom.get(0);
        } else return null;
    }

    @Override
    public void setOnAbortClickListener(Runnable onAbort) {
        this.mBinding.buttonNo.setOnClickListener(v -> {
            if (onAbort != null) onAbort.run();
        });
    }


    private void initializeAdapter(ArrayList<DialogAskClienteClienteDTO> items) {
        DialogAskCliente_Page1_Cliente_ArrayAdapter adapter = new DialogAskCliente_Page1_Cliente_ArrayAdapter(mContext, items);

        AutoCompleteTextView editTextDropdownCliente = mBinding.dropdownCliente;
        editTextDropdownCliente.setThreshold(0);
        editTextDropdownCliente.setAdapter(adapter);
        editTextDropdownCliente.setOnItemClickListener((parent, view, position, id) -> {
            refreshCodJcoms(items.get(position));
        });


        DialogAskCliente_Page1_Commessa_ArrayAdapter commessaAdapter = new DialogAskCliente_Page1_Commessa_ArrayAdapter(mContext);

        AutoCompleteTextView editTextDropdownCommessa = mBinding.dropdownCommessa;
        editTextDropdownCommessa.setThreshold(0);
        editTextDropdownCommessa.setAdapter(commessaAdapter);

        codJcoms.addOnListChangedCallback(new OnListGeneralChangedCallback() {
            @Override
            public void onChanged(ObservableList sender) {
                commessaAdapter.clear();
                commessaAdapter.addAll(codJcoms);
            }
        });
    }

    private void refreshCodJcoms(DialogAskClienteClienteDTO item) {
        codJcoms.clear();
        codJcoms.addAll(item.getCodJcoms());
    }


    private boolean validateCliente() {
        if(SettingsManager.iDB().isFlagAllowEmptyClienteInPickingLibero() && mBinding.inputCliente.getEditText().getText().toString().trim().length() == 0) {
            return true;
        } else return getCurrentCliente() != null;
    }

    public String getCurrentCliente() {
        Optional<DialogAskClienteClienteDTO> result = Stream.of(availableClienti)
                .filter(x -> x.getRagSoc().equalsIgnoreCase(mBinding.inputCliente.getEditText().getText().toString()))
                .findFirst();

        if(result.isPresent()) return result.get().getCodAnag();
        else return null;
    }

    public String getCurrentCommessa() {
        String codAnag = getCurrentCliente();
        Optional<ArrayList<String>> result = Stream.of(availableClienti)
                .filter(x -> x.getCodAnag().equalsIgnoreCase(codAnag))
                .map(DialogAskClienteClienteDTO::getCodJcoms)
                .findFirst();

        if(result.isPresent() && Stream.of(result.get()).anyMatch(x -> x.equalsIgnoreCase(mBinding.inputCommessa.getEditText().getText().toString()))) {
            return mBinding.inputCommessa.getEditText().getText().toString();
        } else return null;
    }


    private void setClienteError(String message) {
        mBinding.inputCliente.setErrorEnabled(true);
        mBinding.inputCliente.setError(message);
        mBinding.inputCliente.setErrorIconDrawable(null);
    }

    private void resetClienteError() {
        mBinding.inputCliente.setError(null);
    }
}
