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

import com.ecep.contract.CustomerFileType;
import com.ecep.contract.ContractFileType;
import com.ecep.contract.DesktopUtils;
import com.ecep.contract.MyDateTimeUtils;
import com.ecep.contract.controller.customer.CompanyCustomerEvaluationFormFileWindowController;
import com.ecep.contract.controller.project.cost.ProjectCostWindowController;
import com.ecep.contract.controller.tab.AbstEntityBasedTabSkin;
import com.ecep.contract.controller.tab.TabSkin;
import com.ecep.contract.converter.CompanyStringConverter;
import com.ecep.contract.converter.EmployeeStringConverter;
import com.ecep.contract.service.*;
import com.ecep.contract.util.UITools;
import com.ecep.contract.vm.ProjectBidViewModel;
import com.ecep.contract.vo.*;
import javafx.application.Platform;
import javafx.beans.property.SimpleObjectProperty;
import javafx.event.ActionEvent;
import javafx.scene.control.Tab;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleGroup;
import javafx.stage.FileChooser;
import javafx.util.converter.LocalDateStringConverter;
import javafx.util.converter.LocalDateTimeStringConverter;
import javafx.util.converter.NumberStringConverter;
import lombok.Setter;

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

public class ProjectBidTabSkinBase
        extends AbstEntityBasedTabSkin<ProjectBidWindowController, ProjectBidVo, ProjectBidViewModel>
        implements TabSkin {

    @Setter
    private LocalDateTimeStringConverter localDateTimeStringConverter;
    @Setter
    private ProjectQuotationService projectQuotationService;
    @Setter
    private LocalDateStringConverter localDateStringConverter;
    @Setter
    private EmployeeStringConverter employeeStringConverter;
    @Setter
    private CompanyStringConverter companyStringConverter;
    @Setter
    private CompanyService companyService;
    @Setter
    private CustomerService customerService;
    @Setter
    private CompanyCustomerFileService customerFileService;
    @Setter
    private ProjectService projectService;
    @Setter
    private ProjectCostService projectCostService;
    @Setter
    private ContractService contractService;
    @Setter
    private ContractFileService contractFileService;

    @Setter
    private CompanyCustomerEvaluationFormFileService evaluationFormFileService;

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

    ProjectCostService getProjectCostService() {
        if (projectCostService == null) {
            projectCostService = getBean(ProjectCostService.class);
        }
        return projectCostService;
    }

    ContractFileService getContractFileService() {
        if (contractFileService == null) {
            contractFileService = getBean(ContractFileService.class);
        }
        return contractFileService;
    }

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

    public ProjectBidTabSkinBase(ProjectBidWindowController controller) {
        super(controller);
    }

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

    void setSelectedToggle(ToggleGroup group, int targetLevel) {
        group.getToggles().stream()
                .filter(toggle -> toggle.getUserData() instanceof Integer)
                .filter(toggle -> (Integer) toggle.getUserData() == targetLevel)
                .findFirst()
                .ifPresent(group::selectToggle);
    }

    @Override
    public void initializeTab() {

        UITools.autoCompletion(controller.applicantField, viewModel.getApplicant(), controller.getEmployeeService());
        controller.applyTimeField.textProperty().bindBidirectional(viewModel.getApplyTime(),
                getLocalDateTimeStringConverter());

        UITools.autoCompletion(controller.authorizerField, viewModel.getAuthorizer(), controller.getEmployeeService());
        controller.authorizationTimeField.textProperty().bindBidirectional(viewModel.getAuthorizationTime(),
                getLocalDateTimeStringConverter());

        // viewModel.getLevel();
        ToggleGroup levelGroup = new ToggleGroup();
        controller.good_radio_btn.setToggleGroup(levelGroup);
        controller.good_radio_btn.setUserData(2);
        controller.bad_radio_btn.setToggleGroup(levelGroup);
        controller.bad_radio_btn.setUserData(1);
        controller.poor_radio_btn.setToggleGroup(levelGroup);
        controller.poor_radio_btn.setUserData(0);
        setSelectedToggle(levelGroup, viewModel.getLevel().get());
        // levelGroup;
        // UI -> ViewModel
        levelGroup.selectedToggleProperty().addListener((obs, oldToggle, newToggle) -> {
            if (newToggle != null && newToggle.getUserData() instanceof Integer) {
                viewModel.getLevel().set((Integer) newToggle.getUserData());
            }
        });

        // ViewModel -> UI: 监听 level 属性变化
        viewModel.getLevel().addListener((obs, oldVal, newVal) -> {
            if (newVal == null)
                return;
            setSelectedToggle(levelGroup, newVal.intValue());
        });

        controller.standardPayWayField.selectedProperty().bindBidirectional(viewModel.getStandardPayWay());
        controller.noStandardPayWayTextField.textProperty().bindBidirectional(viewModel.getNoStandardPayWayText());
        controller.noStandardPayWayTextField.disableProperty().bind(controller.standardPayWayField.selectedProperty());

        controller.standardContractTextField.selectedProperty().bindBidirectional(viewModel.getStandardContractText());
        controller.noStandardContractTextField.textProperty().bindBidirectional(viewModel.getNoStandardContractText());
        controller.noStandardContractTextField.disableProperty()
                .bind(controller.standardContractTextField.selectedProperty());

        controller.amountField.textProperty().bindBidirectional(viewModel.getAmount(),
                new NumberStringConverter(getLocale()));

        UITools.autoCompletion(controller.evaluationFileField, viewModel.getEvaluationFile(),
                getCompanyCustomerFileService());
        controller.evaluationFileBtn.setOnAction(event -> {
            runAsync(() -> {
                Integer fileId = viewModel.getEvaluationFile().get();
                CompanyCustomerEvaluationFormFileVo file = getEvaluationFormFileService().findById(fileId);
                if (file != null) {
                    CompanyCustomerEvaluationFormFileWindowController.show(file,
                            getTab().getTabPane().getScene().getWindow());
                }
            }).exceptionally(this::handleException);
        });

        UITools.autoCompletion(controller.costField, viewModel.getCost(), getProjectCostService());
        controller.costBtn.setOnAction(event -> {
            runAsync(() -> {
                Integer costId = viewModel.getCost().get();
                ProjectCostVo cost = getProjectCostService().findById(costId);
                if (cost != null) {
                    ProjectCostWindowController.show(cost, getTab().getTabPane().getScene().getWindow());
                }
            }).exceptionally(this::handleException);
        });

        controller.authorizationFileField.textProperty().bind(viewModel.getAuthorizationFile().map(File::getName));
        controller.openAuthorizationFileBtn.setOnAction(event -> {
            DesktopUtils.showInExplorer(viewModel.getAuthorizationFile().get());
        });
        controller.openAuthorizationFileBtn.disableProperty().bind(viewModel.getAuthorizationFile().isNull());
        controller.changeAuthorizationFileBtn.setOnAction(this::onChangeAuthorizationFileAction);

        controller.bidAcceptanceLetterFileField.textProperty()
                .bind(viewModel.getBidAcceptanceLetterFile().map(File::getName));
        controller.openBidAcceptanceLetterFileBtn.setOnAction(event -> {
            DesktopUtils.showInExplorer(viewModel.getBidAcceptanceLetterFile().get());
        });
        controller.openBidAcceptanceLetterFileBtn.disableProperty()
                .bind(viewModel.getBidAcceptanceLetterFile().isNull());
        controller.changeBidAcceptanceLetterFileBtn.setOnAction(this::onChangeBidAcceptanceLetterFileAction);

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

        controller.importExcelBtn.setOnAction(event -> {
            FileChooser chooser = new FileChooser();
            chooser.setTitle("导入投标审批表");
            File file = chooser.showOpenDialog(getTab().getTabPane().getScene().getWindow());
            importFromExcel(file);
        });

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

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

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

    }

    private void onChangeAuthorizationFileAction(ActionEvent event) {
        FileChooser fileChooser = new FileChooser();
        setInitialDirectory(fileChooser, viewModel.getAuthorizationFile().get(), viewModel.getProject().get());
        File selectedFile = fileChooser.showOpenDialog(getTab().getTabPane().getScene().getWindow());
        if (selectedFile != null) {
            viewModel.getAuthorizationFile().set(selectedFile);
            // save();
        }
    }

    public void onChangeBidAcceptanceLetterFileAction(ActionEvent event) {
        FileChooser fileChooser = new FileChooser();
        setInitialDirectory(fileChooser, viewModel.getBidAcceptanceLetterFile().get(), viewModel.getProject().get());
        File selectedFile = fileChooser.showOpenDialog(getTab().getTabPane().getScene().getWindow());
        if (selectedFile != null) {
            viewModel.getBidAcceptanceLetterFile().set(selectedFile);
            // save();
        }
    }

    void setInitialDirectory(FileChooser fileChooser, File file, Integer projectId) {
        if (file == null) {
            ProjectVo projectVo = getProjectService().findById(projectId);
            File path = getProjectService().searchPath(projectVo);
            if (path != null) {
                fileChooser.setInitialDirectory(path);
            }
        } else {
            fileChooser.setInitialDirectory(file.getParentFile());
        }
    }

    /**
     * 尝试获取客户资信评估表
     */
    private void tryGetEvaluationFile() {
        Integer projectId = getViewModel().getProject().get();
        ProjectVo project = getProjectService().findById(projectId);
        if (project == null) {
            return;
        }
        Integer companyId = project.getCustomerId();
        CompanyVo company = getCompanyService().findById(companyId);
        CustomerVo customer = getCompanyCustomerService().findByCompany(company);
        if (customer == null) {
            // 没有对应的客户
            return;
        }

        CompanyCustomerFileService fileService = getBean(CompanyCustomerFileService.class);

        // 获取客户资信评估表
        List<CustomerFileVo> list = fileService.findAllByCustomerAndType(customer,
                CustomerFileType.EvaluationForm);
        if (list.isEmpty()) {
            // 没有评估表
            return;
        }

        // 在时间范围内是否有评估表
        LocalDateTime applyTime = getViewModel().getApplyTime().get();
        LocalDate verifyDate = applyTime.toLocalDate();
        CustomerFileVo file = list.stream()
                .filter(v -> v.getSignDate() != null && v.isValid())
                .filter(v -> v.getType() == CustomerFileType.EvaluationForm)
                .filter(v -> MyDateTimeUtils.dateValidFilter(verifyDate, v.getSignDate(), v.getSignDate().plusYears(1),
                        7))
                .findFirst().orElse(null);
        if (file == null) {
            return;
        }

        // 查找评估表对象
        CompanyCustomerEvaluationFormFileVo evaluationFileVo = getEvaluationFormFileService()
                .findByCustomerFile(file);
        if (evaluationFileVo == null) {
            // 没找到对应的评估表对象，跳过
            return;
        }

        Platform.runLater(() -> {
            getViewModel().getEvaluationFile().set(evaluationFileVo.getId());
            Integer creditLevel = evaluationFileVo.getCreditLevel();
            getViewModel().getLevel().set(creditLevel >= 4 ? 2 : creditLevel >= 2 ? 1 : 0);
            save();
        });
    }

    /**
     * 尝试获取授权文件
     */
    private void tryGetAuthorizationFile() {
        getContractFile(viewModel.getAuthorizationFile(), viewModel.getAuthorizationTime(),
                ContractFileType.BidApprovalForm);
    }

    /**
     * 尝试获取中标通知文件
     */
    private void tryGetBidAcceptanceLetterFile() {
        getContractFile(viewModel.getAuthorizationFile(), viewModel.getAuthorizationTime(),
                ContractFileType.BidAcceptanceLetter);
    }

    private void getContractFile(SimpleObjectProperty<File> fileProperty,
            SimpleObjectProperty<LocalDateTime> dateTimeProperty, ContractFileType type) {
        Integer projectId = getViewModel().getProject().get();
        ProjectVo project = getProjectService().findById(projectId);
        if (project == null) {
            return;
        }
        ContractFileService fileService = getContractFileService();
        List<ContractFileVo> list = new ArrayList<>();
        for (ContractVo contract : getContractService().findAllSalesByProject(project)) {
            list.addAll(fileService.findAllByContractAndFileType(contract, type));
        }
        if (list.isEmpty()) {
            return;
        }

        ContractFileVo contractFile = list.stream().max(Comparator.comparing(ContractFileVo::getApplyDate))
                .orElse(null);
        if (contractFile == null) {
            return;
        }

        if (contractFile.getApplyDate() != null && dateTimeProperty.get() == null) {
            LocalDateTime localDateTime = LocalDateTime.of(contractFile.getApplyDate(), LocalTime.MIN);
            dateTimeProperty.set(localDateTime);
        }
        Integer contractId = contractFile.getContractId();
        ContractVo c = getContractService().findById(contractId);
        File file = new File(c.getPath(), contractFile.getFileName());
        if (file.exists()) {
            Platform.runLater(() -> {
                getViewModel().getAuthorizationFile().set(file);
                save();
            });
        }
    }

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

    private void uploadScanFile(File file) {
        // TODO
    }

    private void importFromExcel(File file) {
        // TODO
    }

    private void employeeAutoCompletion(TextField textField, SimpleObjectProperty<Integer> property) {
        UITools.autoCompletion(textField, property, controller.getEmployeeService());
    }

    private void companyAutoCompletion(TextField textField, SimpleObjectProperty<Integer> property) {
        UITools.autoCompletion(textField, property, getCompanyService());
    }

    private ProjectQuotationService getProjectQuotationService() {
        if (projectQuotationService == null) {
            projectQuotationService = getBean(ProjectQuotationService.class);
        }
        return projectQuotationService;
    }

    private LocalDateStringConverter getLocalDateStringConverter() {
        if (localDateStringConverter == null) {
            localDateStringConverter = new LocalDateStringConverter(DateTimeFormatter.ISO_LOCAL_DATE, null);
        }
        return localDateStringConverter;
    }

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

    public CompanyService getCompanyService() {
        if (companyService == null) {
            companyService = getBean(CompanyService.class);
        }
        return companyService;
    }

    private CompanyStringConverter getCompanyStringConverter() {
        if (companyStringConverter == null) {
            companyStringConverter = getBean(CompanyStringConverter.class);
        }
        return companyStringConverter;
    }

    private CustomerService getCompanyCustomerService() {
        if (customerService == null) {
            customerService = getBean(CustomerService.class);
        }
        return customerService;
    }

    private CompanyCustomerFileService getCompanyCustomerFileService() {
        if (customerFileService == null) {
            customerFileService = getBean(CompanyCustomerFileService.class);
        }
        return customerFileService;
    }

    private CompanyCustomerEvaluationFormFileService getEvaluationFormFileService() {
        if (evaluationFormFileService == null) {
            evaluationFormFileService = getBean(CompanyCustomerEvaluationFormFileService.class);
        }
        return evaluationFormFileService;
    }
}
