package com.ecep.contract.controller.tab;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.springframework.util.StringUtils;

import com.ecep.contract.SpringApp;
import com.ecep.contract.controller.customer.SalesOrderWindowController;
import com.ecep.contract.controller.table.AbstEntityTableTabSkin;
import com.ecep.contract.converter.EmployeeStringConverter;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.ContractItem;
import com.ecep.contract.model.Employee;
import com.ecep.contract.model.SalesBillVoucher;
import com.ecep.contract.model.SalesOrder;
import com.ecep.contract.service.ContractService;
import com.ecep.contract.service.SaleOrdersService;
import com.ecep.contract.service.SalesBillVoucherService;
import com.ecep.contract.util.FxmlPath;
import com.ecep.contract.util.ProxyUtils;
import com.ecep.contract.vm.ContractItemComposeViewModel;
import com.ecep.contract.vm.SalesBillVoucherViewModel;
import com.ecep.contract.vm.SalesOrderViewModel;

import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Tab;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.Tooltip;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.util.Callback;
import javafx.util.Duration;
import lombok.Setter;

@FxmlPath("/ui/contract/sale-orders-tab-bill-voucher.fxml")
public class SalesOrderTabSkinBillVoucher
        extends
        AbstEntityTableTabSkin<SalesOrderWindowController, SalesOrder, SalesOrderViewModel, SalesBillVoucher, SalesBillVoucherViewModel>
        implements TabSkin {

    @Setter
    SaleOrdersService saleOrdersService;
    @Setter
    SalesBillVoucherService billVoucherService;
    @Setter
    private EmployeeStringConverter employeeStringConverter;

    /* 以下是合同内容 */
    public TableColumn<SalesBillVoucherViewModel, Number> itemTable_idColumn;
    public TableColumn<SalesBillVoucherViewModel, String> refIdColumn;
    public TableColumn<SalesBillVoucherViewModel, String> codeColumn;
    public TableColumn<SalesBillVoucherViewModel, Employee> employeeColumn;
    public TableColumn<SalesBillVoucherViewModel, Employee> makerColumn;
    public TableColumn<SalesBillVoucherViewModel, Employee> verifierColumn;

    public TableColumn<SalesBillVoucherViewModel, LocalDateTime> makerDateColumn;
    public TableColumn<SalesBillVoucherViewModel, LocalDateTime> verifierDateColumn;
    public TableColumn<SalesBillVoucherViewModel, LocalDateTime> modifyDateColumn;
    public TableColumn<SalesBillVoucherViewModel, String> descriptionColumn;

    public SalesOrderTabSkinBillVoucher(SalesOrderWindowController controller) {
        super(controller);
    }

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

    @Override
    protected SalesBillVoucherService getViewModelService() {
        return getSalesBillVoucherService();
    }

    @Override
    public Map<String, Object> getSpecification(SalesOrder parent) {
        Map<String, Object> params = getSpecification();
        params.put("order", parent.getId());
        return params;
    }

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

        itemTable_idColumn.setCellValueFactory(param -> param.getValue().getId());
        codeColumn.setCellValueFactory(param -> param.getValue().getCode());
        refIdColumn.setCellValueFactory(param -> param.getValue().getRefId().asString());
        employeeColumn.setCellValueFactory(param -> param.getValue().getEmployee());
        employeeColumn.setCellFactory(TextFieldTableCell.forTableColumn(getEmployeeStringConverter()));
        makerColumn.setCellValueFactory(param -> param.getValue().getMaker());
        makerColumn.setCellFactory(TextFieldTableCell.forTableColumn(getEmployeeStringConverter()));
        verifierColumn.setCellValueFactory(param -> param.getValue().getVerifier());
        verifierColumn.setCellFactory(TextFieldTableCell.forTableColumn(getEmployeeStringConverter()));

        makerDateColumn.setCellValueFactory(param -> param.getValue().getMakerDate());
        verifierDateColumn.setCellValueFactory(param -> param.getValue().getVerifierDate());
        modifyDateColumn.setCellValueFactory(param -> param.getValue().getModifyDate());

        descriptionColumn.setCellValueFactory(param -> param.getValue().getDescription());
    }

    @Override
    protected void createContextMenu(ContextMenu contextMenu) {
        MenuItem item2 = new MenuItem("刷新");
        item2.setOnAction(this::onTableRefreshAction);

        MenuItem item3 = new MenuItem("删除");
        item3.setOnAction(this::onTableDeleteAction);

        contextMenu.getItems().addAll(item2, item3);
    }

    SaleOrdersService getSaleOrdersService() {
        if (saleOrdersService == null) {
            saleOrdersService = SpringApp.getBean(SaleOrdersService.class);
        }
        return saleOrdersService;
    }

    SalesBillVoucherService getSalesBillVoucherService() {
        if (billVoucherService == null) {
            billVoucherService = SpringApp.getBean(SalesBillVoucherService.class);
        }
        return billVoucherService;
    }

    private EmployeeStringConverter getEmployeeStringConverter() {
        if (employeeStringConverter == null) {
            employeeStringConverter = getBean(EmployeeStringConverter.class);
        }
        return employeeStringConverter;
    }

    private void sum(ContractItemComposeViewModel model, Contract contract,
            HashMap<String, ContractItemComposeViewModel> map) {
        double inQuantity = map.values().stream().map(ContractItemComposeViewModel::getIn)
                .mapToDouble(v -> v.getQuantity().get()).sum();
        Platform.runLater(() -> model.getIn().getQuantity().set(inQuantity));

        double inTaxAmount = map.values().stream().map(ContractItemComposeViewModel::getIn)
                .mapToDouble(v -> v.getTaxAmount().get()).sum();
        Platform.runLater(() -> model.getIn().getTaxAmount().set(inTaxAmount));

        double inExclusiveTaxAmount = map.values().stream().map(ContractItemComposeViewModel::getIn)
                .mapToDouble(v -> v.getExclusiveTaxAmount().get()).sum();
        Platform.runLater(() -> model.getIn().getExclusiveTaxAmount().set(inExclusiveTaxAmount));

        double outQuantity = map.values().stream().map(ContractItemComposeViewModel::getOut)
                .mapToDouble(v -> v.getQuantity().get()).sum();
        Platform.runLater(() -> model.getOut().getQuantity().set(outQuantity));

        double outTaxAmount = map.values().stream().map(ContractItemComposeViewModel::getOut)
                .mapToDouble(v -> v.getTaxAmount().get()).sum();
        Platform.runLater(() -> model.getOut().getTaxAmount().set(outTaxAmount));

        double outExclusiveTaxAmount = map.values().stream().map(ContractItemComposeViewModel::getOut)
                .mapToDouble(v -> v.getExclusiveTaxAmount().get()).sum();
        Platform.runLater(() -> model.getOut().getExclusiveTaxAmount().set(outExclusiveTaxAmount));
    }

    String makeKey(ContractItem item) {
        return item.getTitle() + "-" + item.getSpecification();
    }

    static class NumberTableCell extends TableCell<SalesBillVoucherViewModel, Double> {
        // "%.1f"
        private final String format;

        public NumberTableCell(String format, String styleClass) {
            this.format = format;
            if (StringUtils.hasText(styleClass)) {
                getStyleClass().add(styleClass);
            }
        }

        @Override
        protected void updateItem(Double item, boolean empty) {
            super.updateItem(item, empty);
            if (empty || item == null) {
                setText(null);
                return;
            }
            setText(String.format(format, item));
        }

        private void setTooltip(ObservableList<ContractItem> list, Function<ContractItem, Double> getPrice) {
            String text = list.stream().map(v -> {
                Contract contract = v.getContract();
                if (!ProxyUtils.isInitialized(contract)) {

                    contract = SpringApp.getBean(ContractService.class).findById(contract.getId());
                }
                Double price = getPrice.apply(v);
                double quantity = v.getQuantity();
                return contract.getCode() + " " + String.format(format, price) + " x " + quantity + " = "
                        + String.format(format, (price * quantity));
            }).collect(Collectors.joining("\n"));
            setTooltip(text);
        }

        private void setTooltip(String text) {
            Tooltip tooltip = getTooltip();
            if (StringUtils.hasText(text)) {
                if (tooltip == null) {
                    tooltip = new Tooltip();
                    setTooltip(tooltip);
                }
                tooltip.setShowDelay(Duration.ZERO);
                tooltip.setHideDelay(Duration.ZERO);
                tooltip.setText(text);
            } else {
                if (tooltip != null) {
                    tooltip.setText(null);
                }
            }
        }
    }

    static class NumberCellFactory implements
            Callback<TableColumn<SalesBillVoucherViewModel, Double>, TableCell<SalesBillVoucherViewModel, Double>> {
        private final String format;
        private final String styleClass;

        public NumberCellFactory(String format, String styleClass) {
            this.format = format;
            this.styleClass = styleClass;
        }

        @Override
        public TableCell<SalesBillVoucherViewModel, Double> call(TableColumn<SalesBillVoucherViewModel, Double> param) {
            NumberTableCell cell = new NumberTableCell(format, styleClass);
            cell.setAlignment(Pos.CENTER_RIGHT);
            return cell;
        }
    }
}
