package com.ecep.contract.controller.inventory;

import java.util.function.Function;

import com.ecep.contract.controller.AbstEntityManagerSkin;
import com.ecep.contract.controller.table.cell.LocalDateFieldTableCell;
import com.ecep.contract.controller.table.cell.LocalDateTimeTableCell;
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.vm.InventoryViewModel;

import javafx.beans.property.Property;
import javafx.event.ActionEvent;
import javafx.scene.control.TableColumn;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.util.converter.CurrencyStringConverter;
import javafx.util.converter.NumberStringConverter;
import lombok.Setter;

public class InventoryManagerSkin extends
        AbstEntityManagerSkin<Inventory, InventoryViewModel, InventoryManagerSkin, InventoryManagerWindowController> {

    @Setter
    private InventoryCatalogService catalogService;

    public InventoryManagerSkin(InventoryManagerWindowController controller) {
        super(controller);
    }

    InventoryService getService() {
        return controller.getViewModelService();
    }

    InventoryCatalogService getInventoryCatalogService() {
        if (catalogService == null) {
            catalogService = getBean(InventoryCatalogService.class);
        }
        return catalogService;
    }

    @Override
    public void initializeTable() {
        getTableView().setEditable(false);

        controller.idColumn.setCellValueFactory(param -> param.getValue().getId());

        controller.nameColumn.setCellValueFactory(param -> param.getValue().getName());
        controller.nameColumn.setCellFactory(TextFieldTableCell.forTableColumn());
        controller.nameColumn.setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getName));

        controller.codeColumn.setCellValueFactory(param -> param.getValue().getCode());
        controller.codeColumn.setCellFactory(TextFieldTableCell.forTableColumn());
        controller.codeColumn.setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getCode));

        controller.catalogColumn.setCellValueFactory(param -> param.getValue().getCatalog());
        EntityStringConverter<InventoryCatalog> catalogStringConverter = new EntityStringConverter<>();
        catalogStringConverter.setInitialized(v -> getInventoryCatalogService().findById(v.getId()));
        catalogStringConverter.setFormater(InventoryCatalog::getName);
        catalogStringConverter.setFromString(v -> getInventoryCatalogService().findByName(v));
        catalogStringConverter.setSuggestion(getInventoryCatalogService()::search);

        controller.catalogColumn.setCellFactory(TextFieldTableCell.forTableColumn(catalogStringConverter));
        controller.catalogColumn.setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getCatalog));

        controller.specificationColumn.setCellValueFactory(param -> param.getValue().getSpecification());
        controller.specificationColumn.setCellFactory(TextFieldTableCell.forTableColumn());
        controller.specificationColumn
                .setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getSpecification));

        controller.unitColumn.setCellValueFactory(param -> param.getValue().getUnit());
        controller.unitColumn.setCellFactory(TextFieldTableCell.forTableColumn());
        controller.unitColumn.setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getUnit));

        controller.purchaseTaxRateColumn.setCellValueFactory(param -> param.getValue().getPurchaseTaxRate());
        controller.purchaseTaxRateColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
        controller.purchaseTaxRateColumn
                .setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getPurchaseTaxRate));

        controller.purchasePriceColumn.setCellValueFactory(param -> param.getValue().getPurchasePrice());
        controller.purchasePriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(new CurrencyStringConverter()));
        // controller.purchasePriceColumn.setOnEditCommit(event ->
        // onColumnEditCommit(event, InventoryViewModel::getPurchasePrice));

        controller.saleTaxRateColumn.setCellValueFactory(param -> param.getValue().getSaleTaxRate());
        controller.saleTaxRateColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
        controller.saleTaxRateColumn
                .setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getSaleTaxRate));

        controller.salePriceColumn.setCellValueFactory(param -> param.getValue().getSalePrice());
        controller.salePriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(new CurrencyStringConverter()));
        // controller.salePriceColumn.setOnEditCommit(event -> onColumnEditCommit(event,
        // InventoryViewModel::getSalePrice));

        controller.createTimeColumn.setCellValueFactory(param -> param.getValue().getCreateTime());
        controller.createTimeColumn.setCellFactory(LocalDateFieldTableCell.forTableColumn());
        controller.createTimeColumn
                .setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getCreateTime));

        controller.updateDateColumn.setCellValueFactory(param -> param.getValue().getUpdateDate());
        controller.updateDateColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
        controller.updateDateColumn
                .setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getUpdateDate));

        controller.descriptionColumn.setCellValueFactory(param -> param.getValue().getDescription());
        controller.descriptionColumn.setCellFactory(TextFieldTableCell.forTableColumn());
        controller.descriptionColumn
                .setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getDescription));
    }

    private <T> void onColumnEditCommit(
            TableColumn.CellEditEvent<InventoryViewModel, T> event,
            Function<InventoryViewModel, Property<T>> supplier) {
        InventoryViewModel row = event.getRowValue();
        supplier.apply(row).setValue(event.getNewValue());
        saveRowData(row);
    }

    @Override
    protected void onTableRowDoubleClickedAction(InventoryViewModel item) {
        showInOwner(InventoryWindowController.class, item);
    }

    @Override
    protected void onTableCreateNewAction(ActionEvent event) {
        Inventory inventory = getService().save(getService().createNewInstance());
        InventoryViewModel viewModel = InventoryViewModel.from(inventory);
        dataSet.add(viewModel);
    }
}
