package com.ecep.contract.controller.project.cost;

import java.io.File;
import java.text.NumberFormat;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CompletableFuture;

import com.ecep.contract.util.ProxyUtils;

import com.ecep.contract.ContractFileType;
import com.ecep.contract.DesktopUtils;
import com.ecep.contract.MyDateTimeUtils;
import com.ecep.contract.controller.tab.AbstEntityBasedTabSkin;
import com.ecep.contract.controller.tab.TabSkin;
import com.ecep.contract.converter.EmployeeStringConverter;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.ContractFile;
import com.ecep.contract.model.Project;
import com.ecep.contract.model.ProjectCost;
import com.ecep.contract.service.ContractFileService;
import com.ecep.contract.service.ContractService;
import com.ecep.contract.service.ProjectService;
import com.ecep.contract.util.UITools;
import com.ecep.contract.vm.ProjectCostViewModel;

import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.scene.control.Tab;
import javafx.stage.FileChooser;
import javafx.util.converter.CurrencyStringConverter;
import javafx.util.converter.LocalDateTimeStringConverter;
import javafx.util.converter.NumberStringConverter;
import lombok.Setter;

public class ProjectCostTabSkinBase
        extends AbstEntityBasedTabSkin<ProjectCostWindowController, ProjectCost, ProjectCostViewModel>
        implements TabSkin {
    @Setter
    LocalDateTimeStringConverter localDateTimeStringConverter;
    ProjectService projectService;

    public ProjectCostTabSkinBase(ProjectCostWindowController controller) {
        super(controller);
    }

    ProjectService getProjectService() {
        if (projectService == null) {
            projectService = getBean(ProjectService.class);
        }
        return projectService;
    }

    private LocalDateTimeStringConverter getLocalDateTimeStringConverter() {
        if (localDateTimeStringConverter == null) {
            localDateTimeStringConverter = new LocalDateTimeStringConverter(
                    DateTimeFormatter.ofPattern(MyDateTimeUtils.DEFAULT_DATETIME_FORMAT_PATTERN), null);
        }
        return localDateTimeStringConverter;
    }

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

    @Override
    public void initializeTab() {
        controller.openFileBtn.setOnAction(event -> {
            DesktopUtils.showInExplorer(viewModel.getAuthorizationFile().get());
        });
        controller.openFileBtn.disableProperty().bind(viewModel.getAuthorizationFile().isNull());
        controller.changeFileBtn.setOnAction(this::onChangeAuthorizationFileAction);

        Platform.runLater(() -> {
            controller.changeFileBtn.textProperty().bind(viewModel.getAuthorizationFile().map(v -> {
                return "更换";
            }).orElse("选择"));
        });

        controller.standardPayWayField.selectedProperty().bindBidirectional(viewModel.getStandardPayWay());
        controller.standardContractTextField.selectedProperty().bindBidirectional(viewModel.getStandardContractText());
        controller.noStandardPayWayTextField.textProperty().bindBidirectional(viewModel.getNoStandardPayWayText());
        controller.noStandardContractTextField.textProperty().bindBidirectional(viewModel.getNoStandardContractText());
        NumberFormat numberInstance = NumberFormat.getNumberInstance(getLocale());
        numberInstance.setMaximumFractionDigits(2);
        numberInstance.setMinimumFractionDigits(2);
        CurrencyStringConverter currencyStringConverter = new CurrencyStringConverter(numberInstance);
        NumberStringConverter numberStringConverter = new NumberStringConverter(getLocale());

        controller.stampTaxField.textProperty().bindBidirectional(viewModel.getStampTax(), numberStringConverter);
        controller.stampTaxField.setOnKeyReleased(event -> viewModel.updateStampTaxFee());
        controller.stampTaxFeeField.textProperty()
                .bind(viewModel.getStampTaxFee().map(currencyStringConverter::toString));
        controller.taxAndSurchargesField.textProperty().bindBidirectional(viewModel.getTaxAndSurcharges(),
                numberStringConverter);
        controller.taxAndSurchargesField.setOnKeyReleased(event -> viewModel.updateTaxAndSurchargesFee());
        controller.taxAndSurchargesFeeField.textProperty()
                .bind(viewModel.getTaxAndSurchargesFee().map(currencyStringConverter::toString));

        controller.grossProfitMarginField.textProperty().bindBidirectional(viewModel.getGrossProfitMargin(),
                numberStringConverter);

        controller.inTaxAmountField.textProperty().bindBidirectional(viewModel.getInTaxAmount(),
                currencyStringConverter);
        controller.inExclusiveTaxAmountField.textProperty().bindBidirectional(viewModel.getInExclusiveTaxAmount(),
                currencyStringConverter);
        controller.outTaxAmountField.textProperty().bindBidirectional(viewModel.getOutTaxAmount(),
                currencyStringConverter);
        controller.outExclusiveTaxAmountField.textProperty().bindBidirectional(viewModel.getOutExclusiveTaxAmount(),
                currencyStringConverter);

        EmployeeStringConverter employeeStringConverter = getBean(EmployeeStringConverter.class);
        // controller.applicantField.textProperty().bindBidirectional(viewModel.getApplicant(),
        // employeeStringConverter);
        // controller.authorizerField.textProperty().bindBidirectional(viewModel.getAuthorizer(),
        // employeeStringConverter);

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

        LocalDateTimeStringConverter converter = getLocalDateTimeStringConverter();
        controller.applyTimeField.textProperty().bindBidirectional(viewModel.getApplyTime(), converter);
        controller.authorizationTimeField.textProperty().bindBidirectional(viewModel.getAuthorizationTime(), converter);

        controller.authorizationFileField.textProperty().bind(viewModel.getAuthorizationFile().map(File::getName));

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

        if (getViewModel().getAuthorizationFile().get() == null) {
            CompletableFuture.runAsync(this::tryGetAuthorizationFile).exceptionally(this::handleException);
        }
    }

    private void onChangeAuthorizationFileAction(ActionEvent event) {
        FileChooser fileChooser = new FileChooser();
        File file = viewModel.getAuthorizationFile().get();
        if (file == null) {
            Project project = viewModel.getProject().get();
            if (project != null) {
                if (!ProxyUtils.isInitialized(project)) {
                    project = getProjectService().findById(project.getId());
                }
                File path = getProjectService().searchPath(project);
                if (path != null) {
                    fileChooser.setInitialDirectory(path);
                }
            }
        } else {
            fileChooser.setInitialDirectory(file.getParentFile());
        }
        File selectedFile = fileChooser.showOpenDialog(getTab().getTabPane().getScene().getWindow());
        if (selectedFile != null) {
            viewModel.getAuthorizationFile().set(selectedFile);
            save();
        }
    }

    private void tryGetAuthorizationFile() {
        Project project = getViewModel().getProject().get();
        if (project == null) {
            return;
        }

        ContractService contractService = getBean(ContractService.class);
        Contract contract = contractService.findSalesByProject(project);
        if (contract == null) {
            return;
        }

        ContractFileService contractFileService = getBean(ContractFileService.class);
        List<ContractFile> list = contractFileService.findAllByContractAndFileType(contract, ContractFileType.CostForm);
        if (list.isEmpty()) {
            return;
        }

        ContractFile contractFile = list.stream()
                .max(Comparator.comparing(ContractFile::getApplyDate, Comparator.nullsLast(Comparator.naturalOrder())))
                .orElse(null);

        if (contractFile.getApplyDate() != null && getViewModel().getAuthorizationTime().get() == null) {
            LocalDateTime localDateTime = LocalDateTime.of(contractFile.getApplyDate(), LocalTime.MIN);
            getViewModel().getAuthorizationTime().set(localDateTime);
        }
        File file = new File(contract.getPath(), contractFile.getFileName());
        if (!file.exists()) {
            return;
        }
        Platform.runLater(() -> {
            getViewModel().getAuthorizationFile().set(file);
            save();
        });

    }
}
