package com.ecep.contract.controller.inventory;

import java.text.NumberFormat;
import java.time.MonthDay;
import java.time.Year;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.ecep.contract.util.ProxyUtils;

import com.ecep.contract.ContractPayWay;
import com.ecep.contract.controller.tab.TabSkin;
import com.ecep.contract.controller.table.AbstEntityTableTabSkin;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.ContractItem;
import com.ecep.contract.model.HistoryPrice;
import com.ecep.contract.model.Inventory;
import com.ecep.contract.model.InventoryHistoryPrice;
import com.ecep.contract.service.ContractItemService;
import com.ecep.contract.service.ContractService;
import com.ecep.contract.service.InventoryHistoryPriceService;
import com.ecep.contract.util.FxmlPath;
import com.ecep.contract.vm.InventoryHistoryPriceViewModel;
import com.ecep.contract.vm.InventoryViewModel;

import javafx.event.ActionEvent;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Tab;
import javafx.scene.control.TableColumn;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.util.converter.CurrencyStringConverter;
import javafx.util.converter.NumberStringConverter;
import lombok.Setter;

@FxmlPath("/ui/inventory/inventory-history-price.fxml")
public class InventoryTabSkinHistoryPrice
        extends
        AbstEntityTableTabSkin<InventoryWindowController, Inventory, InventoryViewModel, InventoryHistoryPrice, InventoryHistoryPriceViewModel>
        implements TabSkin {
    public Button refreshBtn;
    public TableColumn<InventoryHistoryPriceViewModel, Number> idColumn;
    public TableColumn<InventoryHistoryPriceViewModel, Year> yearColumn;
    public TableColumn<InventoryHistoryPriceViewModel, Number> latestSaleTaxColumn;
    public TableColumn<InventoryHistoryPriceViewModel, Number> latestSalePriceColumn;
    public TableColumn<InventoryHistoryPriceViewModel, Number> latestSaleTaxPriceColumn;
    public TableColumn<InventoryHistoryPriceViewModel, MonthDay> latestSalePriceDateColumn;
    public TableColumn<InventoryHistoryPriceViewModel, Number> latestPurchaseTaxColumn;
    public TableColumn<InventoryHistoryPriceViewModel, Number> latestPurchasePriceColumn;
    public TableColumn<InventoryHistoryPriceViewModel, Number> latestPurchaseTaxPriceColumn;
    public TableColumn<InventoryHistoryPriceViewModel, MonthDay> latestPurchasePriceDateColumn;

    public TableColumn<InventoryHistoryPriceViewModel, Number> maxSaleTaxColumn;
    public TableColumn<InventoryHistoryPriceViewModel, Number> maxSalePriceColumn;
    public TableColumn<InventoryHistoryPriceViewModel, Number> maxSaleTaxPriceColumn;
    public TableColumn<InventoryHistoryPriceViewModel, MonthDay> maxSalePriceDateColumn;
    public TableColumn<InventoryHistoryPriceViewModel, Number> maxPurchaseTaxColumn;
    public TableColumn<InventoryHistoryPriceViewModel, Number> maxPurchasePriceColumn;
    public TableColumn<InventoryHistoryPriceViewModel, Number> maxPurchaseTaxPriceColumn;
    public TableColumn<InventoryHistoryPriceViewModel, MonthDay> maxPurchasePriceDateColumn;

    public TableColumn<InventoryHistoryPriceViewModel, Number> miniSaleTaxColumn;
    public TableColumn<InventoryHistoryPriceViewModel, Number> miniSalePriceColumn;
    public TableColumn<InventoryHistoryPriceViewModel, Number> miniSaleTaxPriceColumn;
    public TableColumn<InventoryHistoryPriceViewModel, MonthDay> miniSalePriceDateColumn;
    public TableColumn<InventoryHistoryPriceViewModel, Number> miniPurchaseTaxColumn;
    public TableColumn<InventoryHistoryPriceViewModel, Number> miniPurchasePriceColumn;
    public TableColumn<InventoryHistoryPriceViewModel, Number> miniPurchaseTaxPriceColumn;
    public TableColumn<InventoryHistoryPriceViewModel, MonthDay> miniPurchasePriceDateColumn;

    @Setter
    InventoryHistoryPriceService service;
    @Setter
    ContractService contractService;
    @Setter
    ContractItemService contractItemService;

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

    @Override
    protected InventoryHistoryPriceService getViewModelService() {
        return getService();
    }

    InventoryHistoryPriceService getService() {
        if (service == null) {
            service = getBean(InventoryHistoryPriceService.class);
        }
        return service;
    }

    ContractItemService getContractItemService() {
        if (contractItemService == null) {
            contractItemService = getBean(ContractItemService.class);
        }
        return contractItemService;
    }

    ContractService getContractService() {
        if (contractService == null) {
            contractService = getBean(ContractService.class);
        }
        return contractService;
    }

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

    @Override
    public void initializeTable() {
        super.initializeTable();
        refreshBtn.setOnAction(this::onRefreshAction);

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

        idColumn.setCellValueFactory(param -> param.getValue().getId());
        yearColumn.setCellValueFactory(param -> param.getValue().getYear());

        latestSaleTaxColumn.setCellValueFactory(param -> param.getValue().getLatestSaleTax());
        latestSaleTaxColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
        latestSalePriceColumn.setCellValueFactory(param -> param.getValue().getLatestSalePrice());
        latestSalePriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
        latestSaleTaxPriceColumn.setCellValueFactory(param -> param.getValue().getLatestSaleTaxPrice());
        latestSaleTaxPriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
        latestSalePriceDateColumn.setCellValueFactory(param -> param.getValue().getLatestSalePriceDate());

        latestPurchaseTaxColumn.setCellValueFactory(param -> param.getValue().getLatestPurchaseTax());
        latestPurchaseTaxColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
        latestPurchaseTaxPriceColumn.setCellValueFactory(param -> param.getValue().getLatestPurchaseTaxPrice());
        latestPurchaseTaxPriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
        latestPurchasePriceColumn.setCellValueFactory(param -> param.getValue().getLatestPurchasePrice());
        latestPurchasePriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
        latestPurchasePriceDateColumn.setCellValueFactory(param -> param.getValue().getLatestPurchasePriceDate());

        maxSaleTaxColumn.setCellValueFactory(param -> param.getValue().getMaxSaleTax());
        maxSaleTaxColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
        maxSalePriceColumn.setCellValueFactory(param -> param.getValue().getMaxSalePrice());
        maxSalePriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
        maxSaleTaxPriceColumn.setCellValueFactory(param -> param.getValue().getMaxSaleTaxPrice());
        maxSaleTaxPriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
        maxSalePriceDateColumn.setCellValueFactory(param -> param.getValue().getMaxSalePriceDate());

        maxPurchaseTaxColumn.setCellValueFactory(param -> param.getValue().getMaxPurchaseTax());
        maxPurchaseTaxColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
        maxPurchasePriceDateColumn.setCellValueFactory(param -> param.getValue().getMaxPurchasePriceDate());
        maxPurchasePriceColumn.setCellValueFactory(param -> param.getValue().getMaxPurchasePrice());
        maxPurchasePriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
        maxPurchaseTaxPriceColumn.setCellValueFactory(param -> param.getValue().getMaxPurchaseTaxPrice());
        maxPurchaseTaxPriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));

        miniSaleTaxColumn.setCellValueFactory(param -> param.getValue().getMiniSaleTax());
        miniSaleTaxColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
        miniSalePriceColumn.setCellValueFactory(param -> param.getValue().getMiniSalePrice());
        miniSalePriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
        miniSaleTaxPriceColumn.setCellValueFactory(param -> param.getValue().getMiniSaleTaxPrice());
        miniSaleTaxPriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
        miniSalePriceDateColumn.setCellValueFactory(param -> param.getValue().getMiniSalePriceDate());

        miniPurchaseTaxColumn.setCellValueFactory(param -> param.getValue().getMiniPurchaseTax());
        miniPurchaseTaxColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
        miniPurchasePriceColumn.setCellValueFactory(param -> param.getValue().getMiniPurchasePrice());
        miniPurchasePriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
        miniPurchasePriceDateColumn.setCellValueFactory(param -> param.getValue().getMiniPurchasePriceDate());
        miniPurchaseTaxPriceColumn.setCellValueFactory(param -> param.getValue().getMiniPurchaseTaxPrice());
        miniPurchaseTaxPriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));

    }

    private void onRefreshAction(ActionEvent event) {
        runAsync(() -> {

            HashMap<Integer, InventoryHistoryPrice> historyPriceMap = new HashMap<>();

            for (InventoryHistoryPrice historyPrice : getService().findAllByInventory(getParent())) {
                InventoryHistoryPrice oldValue = historyPriceMap.put(historyPrice.getYear().getValue(), historyPrice);
                if (oldValue != null) {
                    getService().delete(oldValue);
                }
            }

            List<ContractItem> items = getContractItemService().findAllByInventory(getParent());
            items.stream().collect(Collectors.groupingBy(v -> {
                Contract contract = v.getContract();
                if (!ProxyUtils.isInitialized(contract)) {
                    contract = getContractService().findById(contract.getId());
                    v.setContract(contract);
                }
                return contract.getSetupDate().getYear();
            })).forEach((year, list) -> {
                InventoryHistoryPrice historyPrice = historyPriceMap.computeIfAbsent(year, k -> {
                    InventoryHistoryPrice price = new InventoryHistoryPrice();
                    price.setInventory(getParent());
                    price.setYear(year);
                    return price;
                });

                list.stream().collect(Collectors.groupingBy(v -> {
                    Contract contract = v.getContract();
                    return contract.getPayWay();
                })).forEach((payWay, contractItems) -> {
                    if (ContractPayWay.RECEIVE.equals(payWay)) {
                        // 销售
                        list.stream().max(Comparator.comparing(v -> {
                            Contract contract = v.getContract();
                            return contract.getSetupDate();
                        })).ifPresent(v -> update(historyPrice.getLatestSalePrice(), v));

                        list.stream().max(Comparator.comparing(ContractItem::getTaxPrice))
                                .ifPresent(v -> update(historyPrice.getMaxSalePrice(), v));
                        list.stream().min(Comparator.comparing(ContractItem::getTaxPrice))
                                .ifPresent(v -> update(historyPrice.getMiniSalePrice(), v));

                    } else if (ContractPayWay.PAY.equals(payWay)) {
                        // 采购
                        list.stream().max(Comparator.comparing(v -> {
                            Contract contract = v.getContract();
                            return contract.getSetupDate();
                        })).ifPresent(v -> update(historyPrice.getLatestPurchasePrice(), v));

                        list.stream().max(Comparator.comparing(ContractItem::getTaxPrice))
                                .ifPresent(v -> update(historyPrice.getMaxPurchasePrice(), v));
                        list.stream().min(Comparator.comparing(ContractItem::getTaxPrice))
                                .ifPresent(v -> update(historyPrice.getMiniPurchasePrice(), v));
                    } else {

                    }
                });
                getService().save(historyPrice);
            });

            loadTableDataSet();
        });
    }

    void update(HistoryPrice historyPrice, ContractItem item) {
        if (item == null) {
            historyPrice.setTaxRate(0);
            historyPrice.setPreTaxPrice(0);
            historyPrice.setPostTaxPrice(0);
            historyPrice.setMonthDay(null);
            return;
        }
        getContractService();
        Contract contract = item.getContract();
        if (!ProxyUtils.isInitialized(contract)) {
            contract = getContractService().findById(contract.getId());
            item.setContract(contract);
        }
        historyPrice.setTaxRate((float) item.getTaxRate());
        historyPrice.setPreTaxPrice(item.getExclusiveTaxPrice());
        historyPrice.setPostTaxPrice(item.getTaxPrice());
        historyPrice.setMonthDay(MonthDay.from(contract.getSetupDate()));
    }

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

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