package com.ecep.contract.controller.inventory;

import java.text.NumberFormat;
import java.time.format.DateTimeFormatter;
import java.util.function.Consumer;

import org.springframework.util.StringUtils;

import com.ecep.contract.MessageHolder;
import com.ecep.contract.MyDateTimeUtils;
import com.ecep.contract.controller.tab.AbstEntityBasedTabSkin;
import com.ecep.contract.controller.tab.TabSkin;
import com.ecep.contract.controller.table.EditableEntityTableTabSkin;
import com.ecep.contract.converter.EmployeeStringConverter;
import com.ecep.contract.converter.EntityStringConverter;
import com.ecep.contract.model.Inventory;
import com.ecep.contract.model.InventoryCatalog;
import com.ecep.contract.service.InventoryCatalogService;
import com.ecep.contract.service.InventoryService;
import com.ecep.contract.util.UITools;
import com.ecep.contract.vm.InventoryViewModel;

import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.ActionEvent;
import javafx.scene.control.Tab;
import javafx.scene.control.TextField;
import javafx.util.converter.CurrencyStringConverter;
import javafx.util.converter.LocalDateStringConverter;
import javafx.util.converter.LocalDateTimeStringConverter;
import javafx.util.converter.NumberStringConverter;

public class InventoryTabSkinBase
        extends AbstEntityBasedTabSkin<InventoryWindowController, Inventory, InventoryViewModel>
        implements TabSkin, EditableEntityTableTabSkin<Inventory, InventoryViewModel> {

    public InventoryTabSkinBase(InventoryWindowController controller) {
        super(controller);
    }

    InventoryService getService() {
        return getCachedBean(InventoryService.class);
    }

    InventoryCatalogService getCatalogService() {
        return getCachedBean(InventoryCatalogService.class);
    }

    @Override
    public Tab getTab() {
        return controller.baseInfoTab;
    }

    @Override
    public void initializeTab() {
        controller.syncBtn.setOnAction(this::onSyncAction);

        NumberFormat numberInstance = NumberFormat.getNumberInstance(getLocale());
        numberInstance.setMaximumFractionDigits(2);
        numberInstance.setMinimumFractionDigits(2);
        CurrencyStringConverter currencyStringConverter = new CurrencyStringConverter(numberInstance);

        controller.nameField.textProperty().bindBidirectional(viewModel.getName());
        controller.nameLockField.selectedProperty().bindBidirectional(viewModel.getNameLock());
        controller.codeField.textProperty().bind(viewModel.getCode());
        controller.unitField.textProperty().bindBidirectional(viewModel.getUnit());
        controller.specificationField.textProperty().bindBidirectional(viewModel.getSpecification());
        controller.specificationLockField.selectedProperty().bindBidirectional(viewModel.getSpecificationLock());

        EntityStringConverter<InventoryCatalog> catalogConverter = new EntityStringConverter<>();
        catalogConverter.setInitialized(v -> getCatalogService().findById(v.getId()));
        catalogConverter.setFormater(InventoryCatalog::getName);
        catalogConverter.setSuggestion(getCatalogService()::search);
        catalogConverter.setFromString(getCatalogService()::findByName);
        UITools.autoCompletion(controller.catalogField, viewModel.getCatalog(), catalogConverter);

        controller.purchaseTaxRateField.textProperty().bindBidirectional(viewModel.getPurchaseTaxRate(),
                new NumberStringConverter());
        // 采购价
        bindPriceField(controller.purchasePriceField, viewModel.getPurchasePrice(), currencyStringConverter,
                viewModel::updatePurchasePrice);
        bindPriceField(controller.purchaseTaxPriceField, viewModel.getPurchaseTaxPrice(), currencyStringConverter,
                viewModel::updatePurchaseTaxPrice);

        controller.saleTaxRateField.textProperty().bindBidirectional(viewModel.getSaleTaxRate(),
                new NumberStringConverter());
        // 销售价
        bindPriceField(controller.salePriceField, viewModel.getSalePrice(), currencyStringConverter,
                viewModel::updateSalePrice);
        bindPriceField(controller.saleTaxPriceField, viewModel.getSaleTaxPrice(), currencyStringConverter,
                viewModel::updateSaleTaxPrice);

        // 采购价不能大于销售价
        Bindings.greaterThan(viewModel.getPurchasePrice(), viewModel.getSalePrice())
                .addListener((observable, oldValue, newValue) -> {
                    if (newValue) {
                        controller.purchasePriceField.getStyleClass().add("error");
                        controller.salePriceField.getStyleClass().add("error");
                    } else {
                        controller.purchasePriceField.getStyleClass().remove("error");
                        controller.salePriceField.getStyleClass().remove("error");
                    }
                });
        Bindings.greaterThan(viewModel.getPurchaseTaxPrice(), viewModel.getSaleTaxPrice())
                .addListener((observable, oldValue, newValue) -> {
                    if (newValue) {
                        controller.purchaseTaxPriceField.getStyleClass().add("error");
                        controller.saleTaxPriceField.getStyleClass().add("error");
                    } else {
                        controller.purchaseTaxPriceField.getStyleClass().remove("error");
                        controller.saleTaxPriceField.getStyleClass().remove("error");
                    }
                });

        EmployeeStringConverter employeeStringConverter = getBean(EmployeeStringConverter.class);
        UITools.autoCompletion(controller.creatorField, viewModel.getCreator(), employeeStringConverter);
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(MyDateTimeUtils.DEFAULT_DATE_FORMAT_PATTERN);
        controller.createTimeField.textProperty().bindBidirectional(viewModel.getCreateTime(),
                new LocalDateStringConverter(dateFormatter, null));

        UITools.autoCompletion(controller.updaterField, viewModel.getUpdater(), employeeStringConverter);
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter
                .ofPattern(MyDateTimeUtils.DEFAULT_DATETIME_FORMAT_PATTERN);
        controller.updateDateField.textProperty().bindBidirectional(viewModel.getUpdateDate(),
                new LocalDateTimeStringConverter(dateTimeFormatter, null));

        controller.weightUnitField.textProperty().bindBidirectional(viewModel.getWeightUnit());
        controller.sizeUnitField.textProperty().bindBidirectional(viewModel.getSizeUnit());
        controller.volumeUnitField.textProperty().bindBidirectional(viewModel.getVolumeUnit());
        controller.weightField.textProperty().bindBidirectional(viewModel.getWeight(), new NumberStringConverter());
        controller.packagedWeightField.textProperty().bindBidirectional(viewModel.getPackagedWeight(),
                new NumberStringConverter());
        controller.sizeLengthField.textProperty().bindBidirectional(viewModel.getSizeLength(),
                new NumberStringConverter());
        controller.sizeWidthField.textProperty().bindBidirectional(viewModel.getSizeWidth(),
                new NumberStringConverter());
        controller.sizeHeightField.textProperty().bindBidirectional(viewModel.getSizeHeight(),
                new NumberStringConverter());
        controller.volumeField.textProperty().bindBidirectional(viewModel.getVolume(), new NumberStringConverter());
        controller.packagedSizeLengthField.textProperty().bindBidirectional(viewModel.getPackagedSizeLength(),
                new NumberStringConverter());
        controller.packagedSizeWidthField.textProperty().bindBidirectional(viewModel.getPackagedSizeWidth(),
                new NumberStringConverter());
        controller.packagedSizeHeightField.textProperty().bindBidirectional(viewModel.getPackagedSizeHeight(),
                new NumberStringConverter());
        controller.packagedVolumeField.textProperty().bindBidirectional(viewModel.getPackagedVolume(),
                new NumberStringConverter());

        controller.descriptionField.textProperty().bindBidirectional(viewModel.getDescription());
    }

    private void bindPriceField(TextField textField, SimpleDoubleProperty property,
            CurrencyStringConverter stringConverter, Consumer<Double> updater) {
        textField.setText(stringConverter.toString(property.get()));
        property.addListener((observable, oldValue, newValue) -> {
            textField.setText(stringConverter.toString(newValue));
        });
        textField.setOnKeyTyped(event -> {
            Number number = stringConverter.fromString(textField.getText());
            updater.accept(number.doubleValue());
        });
    }

    private void onSyncAction(ActionEvent event) {
        Inventory inventory = getEntity();
        setStatus("开始同步数据...");
        if (inventory == null) {
            setStatus("请选择要同步的数据.");
            return;
        }
        if (!StringUtils.hasText(inventory.getCode())) {
            setStatus("请填写商品编码.");
            return;
        }
        setStatus("正在同步数据...");
        MessageHolder holder = (lv, msg) -> setStatus(msg);
        getService().syncInventory(inventory, holder);

    }

    @Override
    public void deleteRowData(Inventory entity) {
        getService().delete(entity);
    }

    @Override
    public Inventory loadRowData(InventoryViewModel row) {
        return getService().findById(row.getId().get());
    }

    @Override
    public Inventory saveRowData(Inventory entity) {
        return getService().save(entity);
    }
}
