package it.integry.integrywmsnative.gest.contab_doc_interni.edit_form;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ObservableArrayList;
import androidx.recyclerview.widget.LinearLayoutManager;

import com.annimon.stream.Stream;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.inject.Inject;

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.data_store.db.entity.SqlMtbColr;
import it.integry.integrywmsnative.core.data_store.db.entity.SqlMtbColt;
import it.integry.integrywmsnative.core.data_store.db.repository.MtbColrRepository;
import it.integry.integrywmsnative.core.di.BindableBoolean;
import it.integry.integrywmsnative.core.di.BindableInteger;
import it.integry.integrywmsnative.core.di.BindableString;
import it.integry.integrywmsnative.core.expansion.BaseActivity;
import it.integry.integrywmsnative.core.model.MtbAart;
import it.integry.integrywmsnative.core.model.MtbColr;
import it.integry.integrywmsnative.core.model.MtbPartitaMag;
import it.integry.integrywmsnative.core.utility.UtilityDate;
import it.integry.integrywmsnative.databinding.ActivityContabDocInterniEditBinding;
import it.integry.integrywmsnative.gest.contab_doc_interni.dto.GrigliaAcquistiChildDTO;
import it.integry.integrywmsnative.gest.contab_doc_interni.dto.GrigliaAcquistiDTO;
import it.integry.integrywmsnative.gest.contab_doc_interni.dto.TipiDocDTO;
import it.integry.integrywmsnative.gest.contab_doc_interni.edit_form.dialog.selectDocRows.DialogSelectDocRowsView;
import it.integry.integrywmsnative.gest.contab_doc_interni.edit_form.ui.DocumentRowsListAdapter;
import it.integry.integrywmsnative.ui.FabMenuCustomAnimations;
import it.integry.integrywmsnative.view.bottom_sheet__mtb_colr_edit.BottomSheetMtbColrEditView;
import it.integry.integrywmsnative.view.dialogs.DialogCommon;
import it.integry.integrywmsnative.view.dialogs.base.DialogSimpleInputHelper;
import it.integry.integrywmsnative.view.dialogs.input_quantity_v2.DialogInputQuantityV2DTO;
import it.integry.integrywmsnative.view.dialogs.input_quantity_v2.DialogInputQuantityV2View;

public class DocInterniEditFormActivity extends BaseActivity implements DocInterniEditFormViewModel.Listener, BottomSheetMtbColrEditView.Listener {

    private static final String DATA_KEY_DOCUMENT = "document";
    private static final String DATA_KEY_PRODUCTS_LIST = "productsList";
    private static final String DATA_KEY_TIPO_DOC = "docType";

    @Inject
    MtbColrRepository documentRowsRepository;

    @Inject
    DocInterniEditFormViewModel viewModel;

    @Inject
    DialogInputQuantityV2View dialogInputQuantityV2View;


    private int mBarcodeScannerIstanceID;
    private ActivityContabDocInterniEditBinding binding;
    public BindableString documentHeader = new BindableString(true);
    public BindableString documentRifHeader = new BindableString(true);
    public BindableString codDtip = new BindableString();
    public BindableString note = new BindableString();
    public BindableString codMgrp = new BindableString();
    public BindableString codAnag = new BindableString();
    public BindableInteger prodsCount = new BindableInteger(0);
    public BindableBoolean isDocumentExportable = new BindableBoolean(false);
    private final ObservableArrayList<SqlMtbColr> documentRowsObservableList = new ObservableArrayList<>();

    public static Intent newInstance(Context context, SqlMtbColt document, GrigliaAcquistiDTO productList, TipiDocDTO tipoDoc) {
        Intent myIntent = new Intent(context, DocInterniEditFormActivity.class);

        String doc = DataCache.addItem(document);
        String productsKey = DataCache.addItem(productList);
        String docType = DataCache.addItem(tipoDoc);
        myIntent.putExtra(DATA_KEY_DOCUMENT, doc);
        myIntent.putExtra(DATA_KEY_PRODUCTS_LIST, productsKey);
        myIntent.putExtra(DATA_KEY_TIPO_DOC, docType);
        return myIntent;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_contab_doc_interni_edit);
        MainApplication.appComponent
                .docInterniEditFormComponent()
                .create()
                .inject(this);
        SqlMtbColt document = DataCache.retrieveItem(getIntent().getStringExtra(DATA_KEY_DOCUMENT));
        GrigliaAcquistiDTO griglia = DataCache.retrieveItem(getIntent().getStringExtra(DATA_KEY_PRODUCTS_LIST));
        List<GrigliaAcquistiChildDTO> productList = griglia.getGrigliaAcquistiChild();
        TipiDocDTO docType = DataCache.retrieveItem(getIntent().getStringExtra(DATA_KEY_TIPO_DOC));

        this.initViewModel();
        this.viewModel.setDocument(document);
        this.viewModel.setProductsList(productList);
        this.viewModel.setTipoDoc(docType);


        this.initView();
        this.initBindables();
        this.initRecyclerView();
    }

    private void initBindables() {
        SqlMtbColt document = this.viewModel.getDocument();
        this.codDtip.set(document.getCodDtipProvv());
        this.note.set(document.getAnnotazioni());
        if (document.getCodMgrp() != null) {
            this.codMgrp.set(document.getCodMgrp());
        } else {
            binding.mtbGrupContainer.setVisibility(View.GONE);
        }
        if (document.getCodAnag() != null) {
            this.codAnag.set(document.getCodAnag() + (document.getCodVdes() != null ? " - " + document.getCodVdes() : ""));
        } else {
            this.binding.supplierLayout.setVisibility(View.GONE);
        }

        this.documentHeader.set(String.format(this.getString(R.string.doc_interni_doc_header), document.getId(), document.getCodDtipProvv()));

        if (document.getNumDoc() != null && document.getDataDoc() != null) {
            this.documentRifHeader.set(String.format(this.getString(R.string.doc_testata), document.getNumDoc().toString(), document.getDataDoc()));
        } else {
            this.binding.docRifLayout.setVisibility(View.GONE);
        }
    }

    private void initView() {
        binding.setViewModel(this.viewModel);
        binding.setView(this);
        setSupportActionBar(binding.toolbar);
        binding.toolbar.setTitle(R.string.edit_doc);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        FabMenuCustomAnimations.changeIconOnFocus(binding.closeActivityFab, R.drawable.ic_menu_24dp, R.drawable.ic_close_24dp);
        binding.bottomSheetMtbColrEdit.setListener(this);
        binding.bottomSheetMtbColrEdit.init(binding.bottomSheetMtbColrEdit, binding.bottomSheetMtbColrEditBackground);
    }

    private void initViewModel() {
        this.viewModel.init();
        this.viewModel.setListeners(this);
    }

    private void initRecyclerView() {
        this.viewModel.docRows.observe(this, this::refreshList);
        DocumentRowsListAdapter listAdapter = new DocumentRowsListAdapter(this, documentRowsObservableList);
        listAdapter.setEmptyView(binding.scanArtSpinner);
        binding.documentRowsList.setAdapter(listAdapter);
        binding.documentRowsList.setLayoutManager(new LinearLayoutManager(this));
        listAdapter.setOnItemClicked(row -> {
            binding.bottomSheetMtbColrEdit.setMtbColr(sqlToEntity(row));
            binding.bottomSheetMtbColrEdit.expand();
        });
    }

    private void refreshList(List<SqlMtbColr> sqlMtbColrs) {
        this.documentRowsObservableList.clear();
        this.documentRowsObservableList.addAll(this.viewModel.docRows.getValue());
    }


    public void closeEdit() {
        this.onBackPressed();
    }

    public void manualSearch() {
        BarcodeManager.disable();
        DialogSimpleInputHelper.makeInputDialog(this, "Ricerca articolo", null, "Cod articolo / Barcode", this.viewModel::onSearch, BarcodeManager::enable).show();
    }


    @Override
    protected void onStart() {
        super.onStart();
        SqlMtbColt document = this.viewModel.getDocument();
        if (document == null) {
            Toast.makeText(this, "Nesusn documento selezionato!", Toast.LENGTH_SHORT).show();
            closeEdit();
            return;
        }

        if (document.getCodDtip() != null) {
            Toast.makeText(this, "Impossibile modificare un documento esportato", Toast.LENGTH_SHORT).show();
            closeEdit();
            return;
        }

        mBarcodeScannerIstanceID = BarcodeManager.addCallback(new BarcodeCallbackDTO()
                .setOnScanSuccessful(this.viewModel::processBarcode)
                .setOnScanFailed(this::onError));
        this.viewModel.fetchDocumentRows();
    }

    @Override
    protected void onDestroy() {
        BarcodeManager.removeCallback(mBarcodeScannerIstanceID);
        super.onDestroy();
    }

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

    @Override
    public void onRowsChanged(List<SqlMtbColr> rows) {
        this.prodsCount.set(rows.size());
        this.isDocumentExportable.set(rows.size() > 0);
    }

    @Override
    public void onEditRowRequest(SqlMtbColr row, boolean flagTracciabilita) {
        this.onLoadingStarted();
        MtbAart mtbAart = new MtbAart();
        mtbAart.setBarCode(row.getCodBarre());
        mtbAart.setDiacod(row.getCodBarre());
        mtbAart.setCodMart(row.getCodMart());
        mtbAart.setFlagQtaCnfFissa("S");
        mtbAart.setQtaCnf(BigDecimal.valueOf(row.getQtaCnf()));
        mtbAart.setDescrizione(row.getDescrizione());
        mtbAart.setDescrizioneEstesa(row.getDescrizione());
        mtbAart.setFlagTracciabilita(flagTracciabilita ? "S" : "N");
        mtbAart.setUntMis(row.getUntMis());

        DialogInputQuantityV2DTO dialogInputQuantityV2DTO = new DialogInputQuantityV2DTO()
                .setMtbAart(mtbAart)
                .setInitialNumCnf(BigDecimal.valueOf(row.getNumCnf()))
                .setInitialQtaCnf(BigDecimal.valueOf(row.getQtaCnf()))
                .setInitialQtaTot(BigDecimal.valueOf(row.getQtaCol()))
                .setNote(row.getNote())
                .setSaveOnImeDone(true)
                .setPartitaMag(row.getPartitaMag())
                .setDataScad(row.getDataScad())
                .setCanOverflowOrderQuantity(false)
                .setCanLUBeClosed(false)
                .setNotesAllowed(true)
                .setNotesMandatory(this.viewModel.isNotesMandatory())
                .setDataScadMandatory(flagTracciabilita)
                .setCanPartitaMagBeChanged(flagTracciabilita)
                .setNumCnfEditable(false)
                .setSuggestPartitaMag(data -> {
                    Date dataScad = data.getDataScad();
                    String partitaMag = null;
                    if (dataScad != null) {
                        partitaMag = new SimpleDateFormat("yyyymmdd").format(dataScad);
                    }
                    return partitaMag;
                });

        if (!dialogInputQuantityV2View.isAdded())
            dialogInputQuantityV2View.setDialogInputQuantityV2DTO(dialogInputQuantityV2DTO)
                    .setOnComplete((resultDTO, shouldCloseLU) -> {
                        this.onLoadingStarted();
                        this.viewModel.saveRow(row, resultDTO);
                    })
                    .setOnAbort(this::onLoadingEnded)
                    .show(getSupportFragmentManager(), "tag");
    }

    @Override
    public void onDocumentHoldRequest() {
        this.closeEdit();
    }

    @Override
    public void onDocExported() {
        runOnUiThread(() -> {
            DialogCommon.showDataSaved(this, this::closeEdit);
        });
    }

    @Override
    public void onBackPressed() {
        BarcodeManager.removeCallback(mBarcodeScannerIstanceID);
        super.onBackPressed();
    }

    @Override
    public void onMtbColrEdit(MtbColr mtbColr) {
        GrigliaAcquistiChildDTO articolo = viewModel.getArticoloByCodMart(mtbColr.getCodMart());
        this.viewModel.editRow(entityToSql(mtbColr), articolo.getFlagTracciabilita().equalsIgnoreCase("S"));
    }

    @Override
    public void onMtbColrDelete(MtbColr mtbColr) {
        this.viewModel.deleteRow(entityToSql(mtbColr));
    }

    @Override
    public void onMultipleRowsFound(List<SqlMtbColr> rows, GrigliaAcquistiChildDTO articolo) {
        DialogSelectDocRowsView.newInstance(rows, (row) -> {
                    this.onLoadingEnded();
                    if (row != null) {
                        this.viewModel.editRow(row, (articolo.getFlagTracciabilita().equalsIgnoreCase("S")));
                    }
                }
        ).show(this.getSupportFragmentManager(), "dialogSelectDocRows");
    }

    private MtbColr sqlToEntity(SqlMtbColr sqlMtbColr) {
        MtbColr entity = new MtbColr();

        entity
                .setCodMart(sqlMtbColr.getCodMart())
                .setSerCollo(sqlMtbColr.getSerCollo())
                .setGestione(sqlMtbColr.getGestione())
                .setNumCollo(sqlMtbColr.getNumCollo())
                .setDataCollo(UtilityDate.formatDate(sqlMtbColr.getDataCollo(), UtilityDate.COMMONS_DATE_FORMATS.DMY_TIME_SLASH))
                .setRiga(sqlMtbColr.getRiga())
                .setDescrizione(sqlMtbColr.getDescrizione())
                .setUntMis(sqlMtbColr.getUntMis())
                .setCodBarre(sqlMtbColr.getCodBarre())
                .setQtaCnf(BigDecimal.valueOf(sqlMtbColr.getQtaCnf()))
                .setNumCnf(BigDecimal.valueOf(sqlMtbColr.getNumCnf()))
                .setMtbPartitaMag(new MtbPartitaMag().setDataScad(sqlMtbColr.getDataScad()))
                .setQtaCol(BigDecimal.valueOf(sqlMtbColr.getQtaCol()));

        return entity;
    }

    private SqlMtbColr entityToSql(MtbColr mtbColr) {

        return Stream.of(this.viewModel.getDocumentRows())
                .filter(row -> row.getRiga().equals(mtbColr.getRiga()))
                .findFirstOrElse(null);
    }

}
