package it.integry.integrywmsnative.gest.pv_ordini_acquisto;

import android.content.Context;
import android.os.Bundle;
import android.text.Html;
import android.text.SpannableString;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import androidx.appcompat.widget.AppCompatTextView;
import androidx.core.content.ContextCompat;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.LinearLayoutManager;

import com.annimon.stream.Collectors;
import com.annimon.stream.Stream;

import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import it.integry.integrywmsnative.MainApplication;
import it.integry.integrywmsnative.R;
import it.integry.integrywmsnative.core.barcode_reader.BarcodeManager;
import it.integry.integrywmsnative.core.data_store.db.entity.Griglia;
import it.integry.integrywmsnative.core.data_store.db.entity.Ordine;
import it.integry.integrywmsnative.core.data_store.db.repository.ArticoliOrdineRepository;
import it.integry.integrywmsnative.core.data_store.db.repository.ArticoloGrigliaRepository;
import it.integry.integrywmsnative.core.data_store.db.repository.GrigliaRepository;
import it.integry.integrywmsnative.core.data_store.db.repository.OrdineRepository;
import it.integry.integrywmsnative.core.data_store.db.view_model.ArticoloOrdinabileDTO;
import it.integry.integrywmsnative.core.data_store.db.wrappers.OrdineWrapper;
import it.integry.integrywmsnative.core.exception.ExpiredProductListException;
import it.integry.integrywmsnative.core.expansion.BaseFragment;
import it.integry.integrywmsnative.core.interfaces.IPoppableActivity;
import it.integry.integrywmsnative.core.interfaces.IScrollableFragment;
import it.integry.integrywmsnative.core.interfaces.ITitledFragment;
import it.integry.integrywmsnative.core.utility.UtilityDate;
import it.integry.integrywmsnative.core.utility.UtilityString;
import it.integry.integrywmsnative.databinding.FragmentPvOrdiniAcquistoBinding;
import it.integry.integrywmsnative.gest.pv_ordine_acquisto_edit.PVOrdineAcquistoEditActivity;
import it.integry.integrywmsnative.gest.pv_ordini_acquisto.dialogs.DialogScanGrigliaAcquistoView;
import it.integry.integrywmsnative.gest.pv_ordini_acquisto.ui.OrdineAcquistoPvOpenListAdapter;
import it.integry.integrywmsnative.ui.ElevatedToolbar;
import it.integry.integrywmsnative.ui.SimpleDividerItemDecoration;
import it.integry.integrywmsnative.view.dialogs.DialogAskActionView;
import it.integry.integrywmsnative.view.dialogs.base.DialogSimpleMessageView;

public class PVOrdiniAcquistoGrigliaFragment extends BaseFragment implements ITitledFragment, IScrollableFragment {

    private FragmentPvOrdiniAcquistoBinding mBinding;
    private Griglia mGriglia;
    private OrdineAcquistoPvOpenListAdapter mAdapter;
    private final List<OrdineWrapper> mRenderedOrderList = new ArrayList<>();
    private final List<ArticoloOrdinabileDTO> mListArticoli = new ArrayList<>();
    private boolean mRedirectToNewOrder = true;

    private final List<Runnable> mOnPreDestroyList = new ArrayList<>();

    @Inject
    GrigliaRepository mGrigliaRepository;

    @Inject
    ArticoliOrdineRepository mArticoliOrdineRepository;

    @Inject
    ArticoloGrigliaRepository mArticoloGrigliaRepository;

    @Inject
    OrdineRepository mOrdineRepository;

    @Inject
    PVOrdiniAcquistoGrigliaViewModel mPvOrdiniAcquistoGrigliaViewModel;

    public PVOrdiniAcquistoGrigliaFragment() {
        // Gets appComponent from MyApplication available in the base Gradle module
        MainApplication.appComponent
                .pvOrdineAcquistoGrigliaComponent()
                .create()
                .inject(this);
    }

    public static PVOrdiniAcquistoGrigliaFragment newInstance() {
        PVOrdiniAcquistoGrigliaFragment fragment = new PVOrdiniAcquistoGrigliaFragment();
        Bundle args = new Bundle();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        setRetainInstance(true);

        mBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_pv_ordini_acquisto, container, false);
        mBinding.setViewmodel(this);

        init();
        initRecyclerView();
        return mBinding.getRoot();
    }

    private void init() {
        BarcodeManager.enable();
        DialogScanGrigliaAcquistoView.newInstance((griglia, listArticoli) -> {
            if (griglia == null) {
                ((IPoppableActivity) requireActivity()).pop();
            } else {
                setGriglia(griglia);
                setListaArticoli(listArticoli);
                this.onGrigliaRetrieved();
            }
        }).show(requireActivity().getSupportFragmentManager(), "tag");

    }

    @Override
    public void onCreateActionBar(AppCompatTextView titleText, Context context) {
        titleText.setText(context.getText(R.string.pv_elenco_ordiniA_title_fragment).toString());
    }

    private void onGrigliaRetrieved() {
        if (UtilityString.isNullOrEmpty(mGriglia.getCodAlis())) {

            Map<String, Long> downloadedGrids = Stream.of(mListArticoli).collect(Collectors.groupingBy(ArticoloOrdinabileDTO::getCodAlis, Collectors.counting()));
            if (downloadedGrids != null && !downloadedGrids.isEmpty()) {

                List<String> gridsDetails = Stream.of(downloadedGrids)
                        .map((el) -> "<b>" + el.getKey() + ":</b> " + el.getValue() + " " + getResources().getQuantityString(R.plurals.available_articles, el.getValue().intValue()))
                        .toList();


                DialogSimpleMessageView.makeInfoDialog(getText(R.string.grid_details).toString(),
                                Html.fromHtml(
                                        String.format(getResources().getQuantityString(R.plurals.loaded_grids_message, (int) downloadedGrids.size()), downloadedGrids.size())
                                                + "<br /><br />" +
                                                StringUtils.join(gridsDetails, "<br/>")),
                                null,
                                this::fetchOrders)
                        .show(requireActivity().getSupportFragmentManager(), "downloadedGridDetails");
            } else {
                fetchOrders();
            }
        } else {
            fetchOrders();
        }
    }

    private void setGriglia(Griglia griglia) {
        mGriglia = griglia;
        mBinding.fabNewOrder.setVisibility(View.VISIBLE);
        if (UtilityString.isNullOrEmpty(griglia.getCodAlis())) {
            mBinding.infoGriglia.setVisibility(View.GONE);
        } else {
            mBinding.codAlis.setText(griglia.getCodAlis());
            mBinding.descrLis.setText(griglia.getDescrLisa());
        }
        mBinding.descrDepo.setText(griglia.getDescrDepo());
    }

    private void setListaArticoli(List<ArticoloOrdinabileDTO> listArticoli) {
        mListArticoli.clear();
        mListArticoli.addAll(listArticoli);
        Calendar today = Calendar.getInstance();
        today.set(Calendar.MILLISECOND, 0);
        today.set(Calendar.SECOND, 0);
        today.set(Calendar.MINUTE, 0);
        today.set(Calendar.HOUR_OF_DAY, 0);

        this.mPvOrdiniAcquistoGrigliaViewModel.setDataCaricamentoListino(today);
        mBinding.countArtLis.setText(String.valueOf(listArticoli.size()));
    }

    private void fetchOrders() {
        this.onLoadingStarted();

        mOrdineRepository.selectAllOpenOrders(mGriglia.getCodAlis(), ordini -> {
            this.onLoadingEnded();
            requireActivity().runOnUiThread(() -> {
                setOrdini(ordini);
            });
        }, this::onError);
    }

    private void setOrdini(List<OrdineWrapper> ordini) {
        mBinding.ordiniAApertiMainList.setVisibility(ordini != null && ordini.size() > 0 ? View.VISIBLE : View.GONE);
        mBinding.ordiniAEmptyView.setVisibility(ordini == null || ordini.size() <= 0 ? View.VISIBLE : View.GONE);
        refreshRenderedOrdini(ordini);
        mAdapter.updateItems(mRenderedOrderList);
        if (mRenderedOrderList.isEmpty() && mRedirectToNewOrder) {
            createNewOrder();
        } else {
            mRedirectToNewOrder = false;
        }
    }


    private void initRecyclerView() {
        mBinding.ordiniAApertiMainList.setHasFixedSize(true);
        mBinding.ordiniAApertiMainList.setLayoutManager(new LinearLayoutManager(requireActivity()));

        SimpleDividerItemDecoration itemDecorator = new SimpleDividerItemDecoration(requireActivity(), SimpleDividerItemDecoration.VERTICAL);
        itemDecorator.setDrawable(ContextCompat.getDrawable(requireActivity(), R.drawable.divider));
        mBinding.ordiniAApertiMainList.addItemDecoration(itemDecorator);
        mAdapter = new OrdineAcquistoPvOpenListAdapter(requireActivity(), mRenderedOrderList, this::selectAction);
        mBinding.ordiniAApertiMainList.setAdapter(mAdapter);
    }

    private void editOrdine(Ordine ordine) {
        if (this.mPvOrdiniAcquistoGrigliaViewModel.isProductListSessionInvalid()) {
            this.onError(new ExpiredProductListException());
            return;
        }
        requireActivity().startActivity(PVOrdineAcquistoEditActivity.newInstance(requireActivity(), ordine, mListArticoli));
    }


    private void selectAction(Ordine ordine) {
        DialogAskActionView.newInstance(Html.fromHtml(String.format(this.getString(R.string.ord_acq_testata), ordine.getOrdineId(), UtilityDate.formatDate(ordine.getDataIns(), UtilityDate.COMMONS_DATE_FORMATS.DMY_HUMAN))).toString(),
                        mListArticoli.size() + " articoli",
                        () -> this.editOrdine(ordine),
                        () -> this.deleteOrdine(ordine))
                .show(requireActivity().getSupportFragmentManager(), "tag");

    }

    private void deleteOrdine(Ordine ordine) {
        String text = "Stai per eliminare un ordine sei sicuro?";

        DialogSimpleMessageView.makeWarningDialog(new SpannableString(Html.fromHtml(text)), null, () -> requireActivity().runOnUiThread(() -> {
            this.onLoadingStarted();
            mPvOrdiniAcquistoGrigliaViewModel.deleteOrder(ordine, () -> {
                requireActivity().runOnUiThread(() -> {
                    this.onLoadingEnded();
                    Toast.makeText(requireActivity(), "Ordine eliminato!", Toast.LENGTH_SHORT).show();
                    fetchOrders();
                });
            }, this::onError);
        }), () -> {
        }).show(requireActivity().getSupportFragmentManager(), "tag");
    }

    private void refreshRenderedOrdini(List<OrdineWrapper> ordini) {
        mRenderedOrderList.clear();
        mRenderedOrderList.addAll(ordini);
    }

    public void createNewOrder() {
        if (this.mPvOrdiniAcquistoGrigliaViewModel.isProductListSessionInvalid()) {
            this.onError(new ExpiredProductListException());
            return;
        }
        this.onLoadingStarted();

        mPvOrdiniAcquistoGrigliaViewModel.createNewOrder(mGriglia, order -> {
            this.onLoadingEnded();
            requireActivity().runOnUiThread(() -> editOrdine(order));
        }, this::onError);
    }

    @Override
    public void setScrollToolbar(ElevatedToolbar toolbar) {
    }

    @Override
    public void onResume() {
        super.onResume();
        if (mGriglia != null) {
            fetchOrders();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        for (Runnable onPreDestroy : mOnPreDestroyList) {
            onPreDestroy.run();
        }
    }

    @Override
    public void addOnPreDestroy(Runnable onPreDestroy) {
        this.mOnPreDestroyList.add(onPreDestroy);
    }

}
