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

import java.io.File;
import java.time.LocalDate;
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.CompanyCustomerFileType;
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.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.converter.EntityStringConverter;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyCustomer;
import com.ecep.contract.model.CompanyCustomerEvaluationFormFile;
import com.ecep.contract.model.CompanyCustomerFile;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.ContractFile;
import com.ecep.contract.model.Employee;
import com.ecep.contract.model.Project;
import com.ecep.contract.model.ProjectQuotation;
import com.ecep.contract.service.CompanyCustomerFileService;
import com.ecep.contract.service.CompanyCustomerService;
import com.ecep.contract.service.CompanyService;
import com.ecep.contract.service.ContractFileService;
import com.ecep.contract.service.ContractService;
import com.ecep.contract.service.ProjectQuotationService;
import com.ecep.contract.service.ProjectService;
import com.ecep.contract.util.ProxyUtils;
import com.ecep.contract.util.UITools;
import com.ecep.contract.vm.ProjectQuotationViewModel;

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;

public class ProjectQuotationTabSkinBase
        extends AbstEntityBasedTabSkin<ProjectQuotationWindowController, ProjectQuotation, ProjectQuotationViewModel>
        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 CompanyCustomerService customerService;
    @Setter
    private CompanyCustomerFileService customerFileService;
    @Setter
    private ProjectService projectService;

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

    public ProjectQuotationTabSkinBase(ProjectQuotationWindowController 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() {
        controller.openFileBtn.setOnAction(event -> {
            DesktopUtils.showInExplorer(viewModel.getAuthorizationFile().get());
        });
        controller.openFileBtn.disableProperty().bind(viewModel.getAuthorizationFile().isNull());
        controller.changeFileBtn.setOnAction(this::onChangeAuthorizationFileAction);

        employeeAutoCompletion(controller.applicantField, viewModel.getApplicant());
        controller.applyTimeField.textProperty().bindBidirectional(viewModel.getApplyTime(),
                getLocalDateTimeStringConverter());
        employeeAutoCompletion(controller.authorizerField, viewModel.getAuthorizer());
        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.amountField.textProperty().bindBidirectional(viewModel.getAmount(),
                new NumberStringConverter(getLocale()));

        evaluationFileAutoCompletion(controller.evaluationFileField, viewModel.getEvaluationFile());

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

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

        controller.evaluationFileBtn.setOnAction(event -> {
            CompletableFuture.runAsync(() -> {
                CompanyCustomerEvaluationFormFile file = viewModel.getEvaluationFile().get();
                if (file != null) {
                    if (!ProxyUtils.isInitialized(file)) {
                        file = getCompanyCustomerFileService().findCustomerEvaluationFormFileById(file.getId());
                    }
                    CompanyCustomerEvaluationFormFileWindowController.show(file.getCustomerFile(),
                            getTab().getTabPane().getScene().getWindow());
                }
            }).exceptionally(this::handleException);
        });

        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);
        }

    }

    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 tryGetEvaluationFile() {
        Project project = getViewModel().getProject().get();
        if (project == null) {
            return;
        }
        if (!ProxyUtils.isInitialized(project)) {
            project = getProjectService().findById(project.getId());
        }
        Company company = project.getCustomer();
        CompanyCustomer customer = getCompanyCustomerService().findByCompany(company);
        if (customer == null) {
            return;
        }

        CompanyCustomerFileService companyCustomerFileService = getBean(CompanyCustomerFileService.class);
        List<CompanyCustomerFile> list = companyCustomerFileService.findAllByCustomerAndType(customer,
                CompanyCustomerFileType.EvaluationForm);
        if (list.isEmpty()) {
            return;
        }

        LocalDateTime applyTime = getViewModel().getApplyTime().get();
        LocalDate verifyDate = applyTime.toLocalDate();
        CompanyCustomerFile file = list.stream()
                .filter(v -> v.getSignDate() != null && v.isValid())
                .filter(v -> v.getType() == CompanyCustomerFileType.EvaluationForm)
                .filter(v -> MyDateTimeUtils.dateValidFilter(verifyDate, v.getSignDate(), v.getSignDate().plusYears(1),
                        7))
                .findFirst().orElse(null);
        if (file == null) {
            return;
        }

        CompanyCustomerEvaluationFormFile evaluationFile = companyCustomerFileService
                .findCustomerEvaluationFormFileByCustomerFile(file);
        if (evaluationFile == null) {
            return;
        }
        Platform.runLater(() -> {
            getViewModel().getEvaluationFile().set(evaluationFile);
            Integer creditLevel = evaluationFile.getCreditLevel();
            getViewModel().getLevel().set(creditLevel >= 4 ? 2 : creditLevel >= 2 ? 1 : 0);
            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.QuotationApprovalForm);
        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();
        });

    }

    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 evaluationFileAutoCompletion(TextField textField,
            SimpleObjectProperty<CompanyCustomerEvaluationFormFile> property) {
        EntityStringConverter<CompanyCustomerEvaluationFormFile> converter = new EntityStringConverter<>();
        converter.setInitialized(
                formFile -> getCompanyCustomerFileService().findCustomerEvaluationFormFileById(formFile.getId()));
        converter.setFormater(formFile -> {
            CompanyCustomerFile customerFile = formFile.getCustomerFile();
            if (customerFile == null) {
                return "无";
            }
            File file = new File(customerFile.getFilePath());
            return file.getName() + ", 等级：" + formFile.getCreditLevel();
        });
        converter.setSuggestion(searchText -> {
            Project project = getViewModel().getProject().get();
            if (project == null) {
                return null;
            }
            if (!ProxyUtils.isInitialized(project)) {
                project = getProjectService().findById(project.getId());
            }
            Company company = project.getCustomer();
            if (company == null) {
                return null;
            }
            CompanyCustomer customer = getCompanyCustomerService().findByCompany(company);
            if (customer == null) {
                return null;
            }
            return getCompanyCustomerFileService().searchEvaluationFile(customer, searchText);
        });
        UITools.autoCompletion(textField, property, converter).setOnAutoCompleted(event -> {
            CompanyCustomerEvaluationFormFile evaluationFile = event.getCompletion();
            Integer creditLevel = evaluationFile.getCreditLevel();
            viewModel.getLevel().set(creditLevel >= 4 ? 2 : creditLevel >= 2 ? 1 : 0);
            property.set(evaluationFile);
        });
    }

    private void employeeAutoCompletion(TextField textField, SimpleObjectProperty<Employee> property) {
        UITools.autoCompletion(textField, property, getEmployeeStringConverter());
    }

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

    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 CompanyCustomerService getCompanyCustomerService() {
        if (customerService == null) {
            customerService = getBean(CompanyCustomerService.class);
        }
        return customerService;
    }

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