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

import java.io.File;
import java.text.NumberFormat;
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;

import com.ecep.contract.util.ProxyUtils;

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.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.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.ProjectBid;
import com.ecep.contract.model.ProjectCost;
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.ProjectCostService;
import com.ecep.contract.service.ProjectQuotationService;
import com.ecep.contract.service.ProjectService;
import com.ecep.contract.util.UITools;
import com.ecep.contract.vm.ProjectBidViewModel;

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 ProjectBidTabSkinBase
        extends AbstEntityBasedTabSkin<ProjectBidWindowController, ProjectBid, 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 CompanyCustomerService customerService;
    @Setter
    private CompanyCustomerFileService customerFileService;
    @Setter
    private ProjectService projectService;
    @Setter
    private ProjectCostService projectCostService;
    @Setter
    private ContractService contractService;
    @Setter
    private ContractFileService contractFileService;

    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() {

        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.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()));

        evaluationFileAutoCompletion(controller.evaluationFileField, viewModel.getEvaluationFile());
        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);
        });

        projectCostAutoCompletion(controller.costField, viewModel.getCost());
        controller.costBtn.setOnAction(event -> {
            CompletableFuture.runAsync(() -> {
                ProjectCost cost = viewModel.getCost().get();
                if (cost != null) {
                    if (!ProxyUtils.isInitialized(cost)) {
                        cost = getProjectCostService().findById(cost.getId());
                    }
                    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, Project project) {
        if (file == null) {
            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());
        }
    }

    /**
     * 尝试获取客户资信评估表
     */
    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() {
        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) {
        Project project = getViewModel().getProject().get();
        if (project == null) {
            return;
        }
        List<ContractFile> list = new ArrayList<>();
        for (Contract contract : getContractService().findAllSalesByProject(project)) {
            list.addAll(getContractFileService().findAllByContractAndFileType(contract, type));
        }
        if (list.isEmpty()) {
            return;
        }

        ContractFile contractFile = list.stream().max(Comparator.comparing(ContractFile::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);
        }
        Contract c = contractFile.getContract();
        ;
        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 projectCostAutoCompletion(TextField textField, SimpleObjectProperty<ProjectCost> property) {
        EntityStringConverter<ProjectCost> converter = new EntityStringConverter<>();
        converter.setInitialized(formFile -> getProjectCostService().findById(formFile.getId()));
        NumberFormat numberInstance = NumberFormat.getNumberInstance(getLocale());
        numberInstance.setMinimumFractionDigits(2);
        numberInstance.setMaximumFractionDigits(2);
        converter.setFormater(cost -> {
            return "v" + cost.getVersion() + ", GM:" + numberInstance.format(cost.getGrossProfitMargin()) + "%";
        });
        converter.setSuggestion(searchText -> {
            Project project = getViewModel().getProject().get();
            if (project == null) {
                return null;
            }
            return getProjectCostService().findAllByProject(project);
        });
        UITools.autoCompletion(textField, property, converter).setOnAutoCompleted(event -> {
            property.set(event.getCompletion());
        });
    }

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