package it.integry.integrywmsnative.gest.prod_dettaglio_linea;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.Html;
import android.text.InputType;
import android.text.SpannableString;
import android.widget.Toast;

import androidx.databinding.Observable;
import androidx.databinding.ObservableField;

import com.google.android.material.chip.Chip;

import javax.inject.Inject;

import it.integry.barcode_base_android_library.model.BarcodeScanDTO;
import it.integry.integrywmsnative.MainApplication;
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.data_cache.DataCache;
import it.integry.integrywmsnative.core.di.BindableBoolean;
import it.integry.integrywmsnative.core.di.BindableString;
import it.integry.integrywmsnative.core.expansion.BaseActivity;
import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.model.MtbColr;
import it.integry.integrywmsnative.core.utility.UtilityString;
import it.integry.integrywmsnative.core.utility.UtilityToast;
import it.integry.integrywmsnative.databinding.ActivityProdDettaglioLineaBinding;
import it.integry.integrywmsnative.gest.prod_dettaglio_linea.dialogs.BottomSheetLineAction;
import it.integry.integrywmsnative.gest.prod_dettaglio_linea.dialogs.DialogStartProduction;
import it.integry.integrywmsnative.gest.prod_linee_produzione.dto.ProdLineStatusDTO;
import it.integry.integrywmsnative.gest.prod_recupero_materiale.ProdRecuperoMaterialeFragment;
import it.integry.integrywmsnative.gest.spedizione.model.PickedQuantityDTO;
import it.integry.integrywmsnative.view.dialogs.base.DialogSimpleInputHelper;
import it.integry.integrywmsnative.view.dialogs.base.DialogSimpleMessageView;
import it.integry.integrywmsnative.view.dialogs.input_quantity_v2.DialogInputQuantityV2DTO;
import it.integry.integrywmsnative.view.dialogs.input_quantity_v2.DialogInputQuantityV2View;

public class ProdDettaglioLineaActivity extends BaseActivity implements ProdDettaglioLineaViewModel.Listener {

    private static final String DATA_KEY_LINE = "keyLinea";
    private static final String DATA_KEY_FRAGMENT_LISTENER = "onFragmentClose";

    private ActivityProdDettaglioLineaBinding mBinding;
    public final ObservableField<String> listaOrd = new ObservableField<>();
    public final BindableString lineaLabel = new BindableString();
    public final BindableBoolean isStarted = new BindableBoolean(false);
    public final BindableBoolean isPaused = new BindableBoolean(false);
    public final BindableBoolean flagShowProdInfo = new BindableBoolean(false);
    public final BindableString hrNum = new BindableString();
    public final BindableString codMart = new BindableString();
    public final BindableString partitaMag = new BindableString();
    public final BindableString productDescription = new BindableString();
    private Runnable onResumeRunnable = null;

    private int barcodeScannerIstanceID = -1;

    @Inject
    ProdDettaglioLineaViewModel mViewModel;

    @Inject
    DialogInputQuantityV2View mDialogInputQuantityV2View;


    public static Intent newInstance(Context context, ProdLineStatusDTO prodLine) {
        Intent myIntent = new Intent(context, ProdDettaglioLineaActivity.class);
        String keyLine = DataCache.addItem(prodLine);
        myIntent.putExtra(DATA_KEY_LINE, keyLine);
        return myIntent;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding = ActivityProdDettaglioLineaBinding.inflate(getLayoutInflater());
        setContentView(mBinding.getRoot());
        setSupportActionBar(mBinding.toolbar);
        setTitle(R.string.line_details);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        ProdLineStatusDTO lineaProd = DataCache.retrieveItem(getIntent().getStringExtra(DATA_KEY_LINE));
        if (lineaProd == null) {
            Toast.makeText(this, "Selezionare una linea di produzione e riprovare", Toast.LENGTH_SHORT).show();
            close();
            return;
        }

        MainApplication.appComponent
                .prodDettaglioLineaComponent()
                .create()
                .inject(this);


        mViewModel.setListener(this);
        mBinding.setViewModel(mViewModel);
        mBinding.setView(this);
        this.init();
        mViewModel.init(lineaProd);

    }

    private void init() {
        initBarcodeReader();
        mViewModel.lineaProd.observe(this, lineaProd -> {
            this.listaOrd.set(lineaProd.getListaOrd());
            this.lineaLabel.set(lineaProd.getLabel());
            this.isStarted.set(lineaProd.isStarted());
            this.isPaused.set(lineaProd.isPaused());
            this.partitaMag.set(lineaProd.getPartitaMag());
            this.codMart.set(lineaProd.getCodMart());
            this.productDescription.set(lineaProd.getDescrizioneProd());
            this.flagShowProdInfo.set(lineaProd.isStarted() && !UtilityString.isNullOrEmpty(lineaProd.getCodMart()));
            this.hrNum.set(lineaProd.getQtaAllocate().toString());
        });
        listaOrd.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {
            @Override
            public void onPropertyChanged(Observable sender, int propertyId) {
                renderOrdersChips();
            }
        });
        getSupportFragmentManager()
                .setFragmentResultListener(DATA_KEY_FRAGMENT_LISTENER, this, (requestKey, result) -> {
                    if (onResumeRunnable != null) {
                        onResumeRunnable.run();
                        onResumeRunnable = null;
                    }
                });
    }

    private void renderOrdersChips() {
        mBinding.ordersList.removeAllViews();
        String listaOrdString = listaOrd.get();
        if (!UtilityString.isNullOrEmpty(listaOrdString)) {
            for (String ord : listaOrdString.split("\\|")) {
                Chip chip = new Chip(this);
                chip.setClickable(false);
                chip.setText(ord);
                mBinding.ordersList.addView(chip);
            }
        }
    }


    @Override
    public boolean onSupportNavigateUp() {
        onBackPressed();
        return true;
    }

    @Override
    public void onSettingsRequest(ProdLineStatusDTO lineaProd) {
        BottomSheetLineAction.newInstance(lineaProd, this::requestResources, this::requestOrderChange, this::requestProductionStop, this::requestMaterialRecover, BarcodeManager::enable).show(getSupportFragmentManager(), "BottomSheetLineAction");
    }

    @Override
    public void confirmInconsistentDeposit(Runnable onConfirm) {
        this.runOnUiThread(() -> {
            DialogSimpleMessageView.makeWarningDialog(
                    Html.fromHtml("L'articolo che si vuole versare non è compatibile con nessun ordine presente sulla linea!"
                            + "<br /> <br/>" +
                            "Vuoi versarlo comunque?"),
                    null,
                    onConfirm,
                    () -> {
                        onLoadingEnded();
                        BarcodeManager.enable();
                    }
            ).show(getSupportFragmentManager(), "confirmOrderClose");
        });
    }

    @Override
    public void requestQtaVersamento(MtbColr mtbColr,
                                     RunnableArgs<PickedQuantityDTO> onComplete) {
        onLoadingStarted();
        DialogInputQuantityV2DTO dialogInputQuantityV2DTO = new DialogInputQuantityV2DTO()
                .setMtbAart(mtbColr.getMtbAart())
                .setInitialNumCnf(mtbColr.getNumCnf())
                .setInitialQtaCnf(mtbColr.getQtaCnf())
                .setInitialQtaTot(mtbColr.getQtaCol())
                .setTotalQtaAvailable(mtbColr.getQtaCol())
                .setTotalNumCnfAvailable(mtbColr.getNumCnf())
                .setQtaCnfAvailable(mtbColr.getQtaCnf())
                .setPartitaMag(mtbColr.getPartitaMag())
                .setDataScad(mtbColr.getDataScadPartita())
                .setCanOverflowOrderQuantity(false)
                .setCanPartitaMagBeChanged(false)
                .setCanLUBeClosed(false)
                .setFocusOnStart(false);

        if (!mDialogInputQuantityV2View.isVisible())
            this.runOnUiThread(() -> {
                onLoadingEnded();
                mDialogInputQuantityV2View
                        .setDialogInputQuantityV2DTO(dialogInputQuantityV2DTO)
                        .setOnComplete((resultDTO, shouldCloseLU) -> {

                            PickedQuantityDTO pickedQuantityDTO = new PickedQuantityDTO()
                                    .setNumCnf(resultDTO.getNumCnf())
                                    .setQtaCnf(resultDTO.getQtaCnf())
                                    .setQtaTot(resultDTO.getQtaTot())
                                    .setPartitaMag(resultDTO.getPartitaMag())
                                    .setDataScad(resultDTO.getDataScad());

                            onComplete.run(pickedQuantityDTO);

                        })
                        .setOnAbort(this::onLoadingEnded)
                        .show(this.getSupportFragmentManager(), "tag");
            });
        else this.onLoadingEnded();
    }

    public void onLineStop() {
        onBackPressed();
    }


    private void initBarcodeReader() {
        barcodeScannerIstanceID = BarcodeManager.addCallback(new BarcodeCallbackDTO()
                .setOnScanSuccessful(onScanSuccessful)
                .setOnScanFailed(this::onError));

        BarcodeManager.enable();
    }


    public void requestResources() {
        this.onLoadingEnded();
        BarcodeManager.disable();

        this.runOnUiThread(() -> {

            DialogSimpleInputHelper.makeInputDialog(this, "Inserisci il numero di risorse da allocare", this.hrNum.get(), "n. risorse", qta -> {
                this.onLoadingStarted();
                try {
                    Integer hrNum = Integer.parseInt(qta);
                    this.mViewModel.startProductionLine(hrNum);
                } catch (NumberFormatException ex) {
                    this.onError(new Exception("Inserire un numero di risorse valido"));
                }
            }, BarcodeManager::enable, InputType.TYPE_CLASS_NUMBER).show();
        });
    }

    public void requestOrderChange() {
        this.onLoadingEnded();
        this.runOnUiThread(() -> {
            DialogStartProduction.newInstance((dto) -> {
                this.mViewModel.checkBarcodeAndStartOrdine(dto);
            }).show(getSupportFragmentManager(), "DialogStartProduction");
        });
    }

    public void requestProductionStop() {
        this.onLoadingEnded();
        BarcodeManager.disable();
        ProdLineStatusDTO lineaProd = mViewModel.getLineaProd();
        if (UtilityString.isNullOrEmpty(lineaProd.getListaOrd())) {
            mViewModel.stopProduction();
        } else {
            this.confirmOrderClose(() -> {
                mViewModel.stopProduction();
            });
        }


    }

    public void requestMaterialRecover() {
        this.onLoadingEnded();
        BarcodeManager.disable();
        this.runOnUiThread(() -> {
            getSupportFragmentManager()
                    .beginTransaction()
                    .add(R.id.frame_layout_container,
                            ProdRecuperoMaterialeFragment.newInstance(null, DATA_KEY_FRAGMENT_LISTENER))
                    .addToBackStack("ProdRecuperoMaterialeFragment")
                    .commit();

        });


    }

    @Override
    public void successDialog(String message, Runnable onComplete) {
        BarcodeManager.disable();

        this.runOnUiThread(() -> DialogSimpleMessageView.makeSuccessDialog(getResources().getString(R.string.success),
                new SpannableString(message), null, onComplete).show(getSupportFragmentManager(), "successDialog"));

    }

    @Override
    public void showToast(String message, Runnable onComplete) {
        this.runOnUiThread(() -> {
            UtilityToast.showToast(message);
            onComplete.run();
        });
    }

    private final RunnableArgs<BarcodeScanDTO> onScanSuccessful = data -> {
        this.onLoadingStarted();

        this.mViewModel.processBarcodeDTO(data, this::onLoadingEnded);

    };


    @Override
    public void confirmOrderClose(Runnable onConfirm) {
        this.onLoadingEnded();
        this.runOnUiThread(() -> {
            DialogSimpleMessageView.makeWarningDialog(
                    Html.fromHtml("Per completare l'operazione è necessario chiudere gli ordini attualmente aperti sulla linea."
                            + "<br /> <br/>" +
                            "Continuare?"),
                    null,
                    () -> {
                        DialogSimpleMessageView.makeInfoDialog(
                                null,
                                Html.fromHtml("Vuoi recuperare del materiale prima di chiudere gli ordini?"),
                                null,
                                () -> {
                                    onResumeRunnable = onConfirm;
                                    this.requestMaterialRecover();
                                },
                                onConfirm
                        ).show(getSupportFragmentManager(), "confirmOrderClose");
                    },
                    BarcodeManager::enable
            ).show(getSupportFragmentManager(), "confirmOrderClose");
        });
    }


    public void close() {
        onBackPressed();
    }

    @Override
    public void onBackPressed() {
        int count = getSupportFragmentManager().getBackStackEntryCount();
        if (count > 0) {
            getSupportFragmentManager().popBackStack();
        } else {
            BarcodeManager.removeCallback(barcodeScannerIstanceID);
            super.onBackPressed();
        }
    }

}
