package com.ecep.contract.controller.project;

import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Stream;

import org.springframework.util.StringUtils;

import com.ecep.contract.util.ComboBoxUtils;
import com.ecep.contract.controller.tab.TabSkin;
import com.ecep.contract.converter.EmployeeStringConverter;
import com.ecep.contract.service.DeliverySignMethodService;
import com.ecep.contract.service.EmployeeService;
import com.ecep.contract.service.ProductTypeService;
import com.ecep.contract.service.ProductUsageService;
import com.ecep.contract.service.ProjectCostService;
import com.ecep.contract.service.ProjectIndustryService;
import com.ecep.contract.service.ProjectSaleTypeService;
import com.ecep.contract.service.ProjectTypeService;
import com.ecep.contract.util.UITools;
import com.ecep.contract.vo.DeliverySignMethodVo;
import com.ecep.contract.vo.ProductTypeVo;
import com.ecep.contract.vo.ProductUsageVo;
import com.ecep.contract.vo.ProjectCostVo;
import com.ecep.contract.vo.ProjectIndustryVo;
import com.ecep.contract.vo.ProjectSaleTypeVo;
import com.ecep.contract.vo.ProjectTypeVo;
import com.ecep.contract.vo.ProjectVo;

import javafx.beans.binding.Bindings;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.event.ActionEvent;
import javafx.scene.control.Tab;
import javafx.util.converter.LocalDateStringConverter;
import javafx.util.converter.NumberStringConverter;
import lombok.Setter;

/**
 * 基础信息
 */
public class ProjectTabSkinBase extends AbstProjectBasedTabSkin implements TabSkin {
    @Setter
    EmployeeStringConverter employeeStringConverter;
    @Setter
    LocalDateStringConverter localDateStringConverter;
    @Setter
    EmployeeService employeeService;

    @Setter
    private DeliverySignMethodService deliverySignMethodService;

    public ProjectTabSkinBase(ProjectWindowController controller) {
        super(controller);
    }

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

    private EmployeeService getEmployeeService() {
        return getBean(EmployeeService.class);
    }

    private ProjectTypeService getProjectTypeService() {
        return getBean(ProjectTypeService.class);
    }

    private ProductTypeService getProductTypeService() {
        return getBean(ProductTypeService.class);
    }

    private ProjectSaleTypeService getSaleTypeService() {
        return getBean(ProjectSaleTypeService.class);
    }

    private ProductUsageService getProductUsageService() {
        return getBean(ProductUsageService.class);
    }

    private ProjectIndustryService getProjectIndustryService() {
        return getBean(ProjectIndustryService.class);
    }

    private DeliverySignMethodService getDeliverySignMethodService() {
        return getBean(DeliverySignMethodService.class);
    }

    @Override
    public void initializeTab() {
        controller.deleteBtn.setOnAction(this::onDeleteAction);
        controller.nameField.textProperty().bindBidirectional(viewModel.getName());
        controller.codeField.textProperty().bind(viewModel.getCode());
        NumberStringConverter stringConverter = new NumberStringConverter();
        Bindings.bindBidirectional(controller.codeYearField.textProperty(), viewModel.getCodeYear(), stringConverter);
        Bindings.bindBidirectional(controller.codeSequenceNumberField.textProperty(), viewModel.getCodeSequenceNumber(),
                stringConverter);

        controller.addressField.textProperty().bindBidirectional(viewModel.getAddress());
        controller.useBidField.selectedProperty().bindBidirectional(viewModel.getUseBid());
        controller.useOfferField.selectedProperty().bindBidirectional(viewModel.getUseOffer());
        controller.standardPayWayField.selectedProperty().bindBidirectional(viewModel.getStandardPayWay());
        Bindings.bindBidirectional(controller.amountField.textProperty(), viewModel.getAmount(),
                new NumberStringConverter());

        ComboBoxUtils.initialComboBox(controller.saleTypeField, viewModel.getSaleType(), getSaleTypeService(), true);
        ComboBoxUtils.initialComboBox(controller.projectTypeField, viewModel.getProjectType(), getProjectTypeService(),
                true);
        ComboBoxUtils.initialComboBox(controller.saleTypeField, viewModel.getSaleType(), getSaleTypeService(), true);
        ComboBoxUtils.initialComboBox(controller.industryField, viewModel.getIndustry(), getProjectIndustryService(),
                true);
        ComboBoxUtils.initialComboBox(controller.productTypeField, viewModel.getProductType(), getProductTypeService(),
                true);
        ComboBoxUtils.initialComboBox(controller.productUsageField, viewModel.getProductUsage(),
                getProductUsageService(), true);
        ComboBoxUtils.initialComboBox(controller.deliverySignMethodField, viewModel.getDeliverySignMethod(),
                getDeliverySignMethodService(), true);

        controller.saleTypeField.valueProperty().addListener((observable, oldValue, newValue) -> {
            Predicate<DeliverySignMethodVo> predicate = p -> {
                return p == null || Objects.equals(p.getSaleTypeId(), newValue.getId());
            };

            ObservableList<DeliverySignMethodVo> items = controller.deliverySignMethodField.getItems();
            if (items instanceof FilteredList<DeliverySignMethodVo> filteredList) {
                filteredList.setPredicate(predicate);
            } else {
                items = items.filtered(predicate);
                controller.deliverySignMethodField.setItems(items);
            }
        });

        // initializeDeliverySignMethodField(controller.saleTypeField,
        // controller.deliverySignMethodField); // Changed from
        // initializeDeliverySignMethodField(ComboBox<ProjectSaleType>
        // saleTypeField,
        // ComboBox<DeliverySignMethod>
        // field)

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

        UITools.autoCompletion(controller.applicantField, viewModel.getApplicant(), getEmployeeService());
        UITools.autoCompletion(controller.authorizerField, viewModel.getAuthorizer(), getEmployeeService());

        controller.createdField.setConverter(localDateStringConverter);
        controller.createdField.valueProperty().bindBidirectional(viewModel.getCreated());
        controller.plannedStartTimeField.setConverter(localDateStringConverter);
        controller.plannedStartTimeField.valueProperty().bindBidirectional(viewModel.getPlannedStartTime());
        controller.plannedCompletionTimeField.setConverter(localDateStringConverter);
        controller.plannedCompletionTimeField.valueProperty().bindBidirectional(viewModel.getPlannedCompletionTime());

        controller.versionLabel.textProperty().bind(viewModel.getVersion().asString());
    }

    private void onDeleteAction(ActionEvent event) {
        ProjectCostService projectCostService = getBean(ProjectCostService.class);
        ProjectVo project = getEntity();
        for (ProjectCostVo cost : projectCostService.findAllByProject(project)) {
            projectCostService.delete(cost);
        }
        getProjectService().delete(project);
        controller.root.getScene().getWindow().hide();
    }

    public void save() {
        makeProjectCode();
        super.save();
    }

    private void makeProjectCode() {
        StringBuilder sb = new StringBuilder();

        ProjectSaleTypeVo saleType = controller.saleTypeField.getValue();
        if (saleType == null) {
            sb.append("_");
        } else {
            controller.saleTypeField.getItems().stream()
                    .filter(item -> item != null && item.getId().equals(saleType.getId()))
                    .findFirst()
                    .ifPresent(item -> sb.append(item.getCode()));
        }

        int year = 0;
        {
            String text = controller.codeYearField.getText();
            if (StringUtils.hasText(text)) {
                year = Integer.parseInt(text);
            }
        }
        if (year < 10) {
            sb.append("0");
        }
        sb.append(year);

        int sn = 0;
        {
            String text = controller.codeSequenceNumberField.getText();
            if (StringUtils.hasText(text)) {
                sn = Integer.parseInt(text);
            }
        }
        if (sn < 10) {
            sb.append("00");
        } else if (sn < 100) {
            sb.append("0");
        }
        sb.append(sn);

        DeliverySignMethodVo signMethod = controller.deliverySignMethodField.getValue();
        ProductTypeVo productType = controller.productTypeField.getValue();
        ProjectTypeVo projectType = controller.projectTypeField.getValue();
        ProjectIndustryVo industry = controller.industryField.getValue();
        ProductUsageVo productUsage = controller.productUsageField.getValue();

        if (!Stream.of(signMethod, productType, projectType, industry, productUsage)
                .allMatch(Objects::isNull)) {
            if (signMethod == null) {
                sb.append("_");
            } else {
                controller.deliverySignMethodField.getItems().stream()
                        .filter(item -> item != null && item.getId().equals(signMethod.getId()))
                        .findFirst()
                        .ifPresent(item -> sb.append(item.getCode()));
            }

            if (productType == null) {
                sb.append("_");
            } else {
                controller.productTypeField.getItems().stream()
                        .filter(item -> item != null && item.getId().equals(productType.getId()))
                        .findFirst()
                        .ifPresent(item -> sb.append(item.getCode()));
            }

            if (projectType == null) {
                sb.append("_");
            } else {
                controller.projectTypeField.getItems().stream()
                        .filter(item -> item != null && item.getId().equals(projectType.getId()))
                        .findFirst()
                        .ifPresent(item -> sb.append(item.getCode()));
            }

            if (industry != null) {
                controller.industryField.getItems().stream()
                        .filter(item -> item != null && item.getId().equals(industry.getId()))
                        .findFirst()
                        .ifPresent(item -> sb.append(item.getCode()));
            } else {
                sb.append("_");
            }

            if (productUsage != null) {
                controller.productUsageField.getItems().stream()
                        .filter(item -> item != null && item.getId().equals(productUsage.getId()))
                        .findFirst()
                        .ifPresent(item -> sb.append(item.getCode()));
            }
        }

        viewModel.getCode().set(sb.toString());
    }

}
