package com.ecep.contract.controller.customer;

import java.io.File;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Consumer;

import org.springframework.util.StringUtils;

import com.ecep.contract.CompanyCustomerFileType;
import com.ecep.contract.DesktopUtils;
import com.ecep.contract.Message;
import com.ecep.contract.MyDateTimeUtils;
import com.ecep.contract.SpringApp;
import com.ecep.contract.constant.CompanyCustomerConstant;
import com.ecep.contract.controller.table.EditableEntityTableTabSkin;
import com.ecep.contract.model.BaseEnumEntity;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyCustomer;
import com.ecep.contract.model.CompanyCustomerFile;
import com.ecep.contract.model.CompanyCustomerFileTypeLocal;
import com.ecep.contract.service.CompanyCustomerFileService;
import com.ecep.contract.service.CompanyCustomerService;
import com.ecep.contract.util.FileUtils;
import com.ecep.contract.util.FxmlPath;
import com.ecep.contract.util.ProxyUtils;
import com.ecep.contract.util.UITools;
import com.ecep.contract.vm.CompanyCustomerFileViewModel;

import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.collections.ObservableMap;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Tab;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import lombok.Setter;

@FxmlPath("/ui/company/customer/customer-tab-file.fxml")
public class CustomerTabSkinFile
        extends AbstCompanyCustomerTableTabSkin<CompanyCustomerFile, CompanyCustomerFileViewModel>
        implements EditableEntityTableTabSkin<CompanyCustomerFile, CompanyCustomerFileViewModel> {

    @Setter
    private CompanyCustomerFileService companyCustomerFileService;

    public TableColumn<CompanyCustomerFileViewModel, Number> fileTable_idColumn;
    public TableColumn<CompanyCustomerFileViewModel, String> fileTable_typeColumn;
    public TableColumn<CompanyCustomerFileViewModel, String> fileTable_filePathColumn;
    public TableColumn<CompanyCustomerFileViewModel, String> fileTable_editFilePathColumn;
    public TableColumn<CompanyCustomerFileViewModel, LocalDate> fileTable_signDateColumn;
    public TableColumn<CompanyCustomerFileViewModel, Boolean> fileTable_validColumn;
    public TableColumn<CompanyCustomerFileViewModel, String> fileTable_descriptionColumn;

    public Button fileTable_reBuildBtn;
    public Button fileTable_updateEvaluationFormBuildBtn;
    public Button fileTable_calcNextSignDateBtn;
    public MenuItem fileTable_menu_refresh;
    public MenuItem fileTable_menu_add;
    public MenuItem fileTable_menu_del;

    public CustomerTabSkinFile(CompanyCustomerWindowController controller) {
        super(controller);
        setDragAndDrop(true);
        setDragAndDropFileHandler(this::moveFileToCustomer);
    }

    // 文件 tab
    @Override
    public Tab getTab() {
        return controller.fileTab;
    }

    @Override
    protected CompanyCustomerFileService getViewModelService() {
        return getCompanyCustomerFileService();
    }

    @Override
    public Map<String, Object> getSpecification(CompanyCustomer parent) {
        Map<String, Object> params = getSpecification();
        params.put("customer", parent.getId());
        return params;
    }

    @Override
    public void initializeTable() {
        super.initializeTable();

        TableView<CompanyCustomerFileViewModel> table = getTableView();

        table.disableProperty().bind(viewModel.getPath().isEmpty());
        fileTable_idColumn.setCellValueFactory(param -> param.getValue().getId());

        ObservableMap<CompanyCustomerFileType, CompanyCustomerFileTypeLocal> observableMapByLocal = FXCollections
                .observableMap(companyCustomerFileService.getFileTypeLocalMap(getLocale()));
        fileTable_typeColumn.setCellValueFactory(param -> Bindings.valueAt(observableMapByLocal,
                param.getValue().getType()).map(BaseEnumEntity::getValue));

        fileTable_filePathColumn.setCellValueFactory(param -> param.getValue().getFilePath());
        fileTable_filePathColumn.setCellFactory(param -> new FileTableFilePathTableCell());
        fileTable_editFilePathColumn.setCellValueFactory(param -> param.getValue().getEditFilePath());
        fileTable_editFilePathColumn.setCellFactory(param -> new FileTableFilePathTableCell());
        fileTable_signDateColumn.setCellValueFactory(param -> param.getValue().getSignDate());
        fileTable_validColumn.setEditable(true);
        fileTable_validColumn.setCellValueFactory(param -> param.getValue().getValid());
        fileTable_validColumn.setCellFactory(param -> new CheckBoxTableCell<>());

        table.setOnDragOver(event -> {
            Dragboard dragboard = event.getDragboard();
            if (dragboard.hasFiles()) {
                event.acceptTransferModes(TransferMode.MOVE);
            }
            event.consume();
        });

        table.setOnDragDropped(event -> {
            Dragboard dragboard = event.getDragboard();
            boolean success = false;
            if (dragboard.hasFiles()) {
                List<File> files = dragboard.getFiles();
                CompletableFuture.runAsync(() -> {
                    try {
                        moveFileToCustomer(files);
                    } catch (Exception e) {
                        UITools.showExceptionAndWait("移动文件出错", e);
                    }
                });
            }
            event.setDropCompleted(success);
            event.consume();
        });

        fileTable_reBuildBtn.setOnAction(this::onFileReBuildingAction);
        fileTable_updateEvaluationFormBuildBtn.setOnAction(this::onUpdateEvaluationFormAction);
        fileTable_calcNextSignDateBtn.setOnAction(this::onCalcNextSignDateAction);

        fileTable_menu_refresh.setOnAction(this::onTableRefreshAction);
        fileTable_menu_add.setOnAction(this::onTableDeleteAction);
        fileTable_menu_del.setOnAction(this::onFileTableMoveToCompanyPathAction);
    }

    @Override
    protected void onTableRowDoubleClickedAction(CompanyCustomerFileViewModel item) {
        CompanyCustomerFileType fileType = item.getType().get();
        if (fileType == CompanyCustomerFileType.EvaluationForm) {
            // 文件不是 Excel 文件时，打开编辑UI
            if (!FileUtils.withExtensions(item.getFilePath().get(), FileUtils.XLS,
                    FileUtils.XLSX)) {
                CompanyCustomerEvaluationFormFileWindowController.show(item, controller.root.getScene().getWindow());
                return;
            }
        }
        File file = new File(item.getFilePath().get());
        if (!file.exists()) {
            setStatus("文件不存在 " + file.getName());
            return;
        }
        DesktopUtils.showInExplorer(file);
    }

    private void moveFileToCustomer(List<File> files) {
        String path = viewModel.getPath().get();
        if (!StringUtils.hasText(path)) {
            setStatus("未设置目录");
            return;
        }
        File dir = new File(path);
        if (!dir.exists()) {
            setStatus("目录错误,不存在");
            return;
        }
        CompanyCustomer companyCustomer = getParent();
        LocalDate nextSignDate = getCompanyCustomerFileService().getNextSignDate(companyCustomer,
                ((level, message) -> setStatus(message)));
        if (nextSignDate != null && files.size() == 1) {
            File file = files.getFirst();
            String fileName = file.getName();
            if (fileName.startsWith("S")) {
                String destFileName = CompanyCustomerConstant.EVALUATION_FORM_NAME2 + "_"
                        + MyDateTimeUtils.format(nextSignDate)
                        + "." + StringUtils.getFilenameExtension(fileName);
                File dest = new File(dir, destFileName);
                if (file.renameTo(dest)) {
                    CompanyCustomerFile ccf = new CompanyCustomerFile();
                    ccf.setCustomer(companyCustomer);
                    ccf.setType(CompanyCustomerFileType.EvaluationForm);
                    ccf.setFilePath(dest.getAbsolutePath());
                    ccf.setSignDate(nextSignDate);
                    ccf.setValid(false);
                    CompanyCustomerFile saved = getCompanyCustomerFileService().save(ccf);
                    Platform.runLater(() -> {
                        CompanyCustomerFileViewModel model = new CompanyCustomerFileViewModel();
                        model.update(saved);
                        dataSet.add(model);
                        CompanyCustomerEvaluationFormFileWindowController.show(model,
                                getTableView().getScene().getWindow());
                    });
                    return;
                }
            }

        }

        List<CompanyCustomerFile> companyCustomerFiles = new ArrayList<>();
        for (File file : files) {
            File dest = new File(dir, file.getName());
            if (file.renameTo(dest)) {
                CompanyCustomerFile ccf = new CompanyCustomerFile();
                ccf.setCustomer(companyCustomer);
                ccf.setType(CompanyCustomerFileType.General);
                ccf.setFilePath(dest.getAbsolutePath());
                ccf.setValid(false);
                companyCustomerFiles.add(ccf);
            }
        }

        getCompanyCustomerFileService().saveAll(companyCustomerFiles);

        loadTableDataSet();
    }

    public void onFileReBuildingAction(ActionEvent event) {
        CompletableFuture.runAsync(() -> {
            CompanyCustomerService customerService = getCompanyCustomerService();
            try {
                CompanyCustomer companyCustomer = customerService.findById(viewModel.getId().get());
                if (customerService.reBuildingFiles(companyCustomer, (level, message) -> setStatus(message))) {
                    loadTableDataSet();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    @Override
    public CompanyCustomerFile loadRowData(CompanyCustomerFileViewModel row) {
        return getCompanyCustomerFileService().findById(row.getId().get());
    }

    @Override
    public CompanyCustomerFile saveRowData(CompanyCustomerFile entity) {
        return getCompanyCustomerFileService().save(entity);
    }

    @Override
    public void deleteRowData(CompanyCustomerFile entity) {
        getCompanyCustomerFileService().delete(entity);
    }

    @Override
    protected boolean deleteRow(CompanyCustomerFileViewModel row) {
        String path = row.getFilePath().get();
        if (super.deleteRow(row)) {
            File file = new File(path);
            if (file.exists()) {
                UITools.showConfirmation("数据记录已经删除，请确认是否删除物理文件", path)
                        .thenAccept(buttonType -> {
                            if (buttonType == ButtonType.OK) {
                                if (file.delete()) {
                                    setStatus("删除文件 " + path);
                                }
                            }
                        });
            }
            return true;
        }
        return false;
    }

    public void onFileTableMoveToCompanyPathAction(ActionEvent event) {
        Company company = viewModel.getCompany().get();
        if (!ProxyUtils.isInitialized(company)) {
            company = getCompanyService().findById(company.getId());
        }
        viewModel.getCompany().set(company);

        if (!StringUtils.hasText(company.getPath())) {
            setStatus("公司目录未设置");
            return;
        }

        File companyPath = new File(company.getPath());
        if (!companyPath.exists()) {
            setStatus("公司目录设置设置异常，无法访问");
            return;
        }

        CompanyCustomerFileViewModel selectedItem = getSelectedItem();
        if (selectedItem == null) {
            return;
        }
        String filePath = selectedItem.getFilePath().get();
        String editFilePath = selectedItem.getEditFilePath().get();

        if (StringUtils.hasText(filePath)) {
            File file = new File(filePath);
            if (file.exists()) {
                File dest = new File(companyPath, file.getName());
                if (file.renameTo(dest)) {
                    setStatus(file.getAbsolutePath() + " -> " + dest.getAbsolutePath());
                }
            }
        }

        if (StringUtils.hasText(editFilePath)) {
            File file = new File(editFilePath);
            if (file.exists()) {
                File dest = new File(companyPath, file.getName());
                if (file.renameTo(dest)) {
                    setStatus(file.getAbsolutePath() + " -> " + dest.getAbsolutePath());
                }
            }
        }

        deleteRow(selectedItem);

        // getCompanyCustomerService().deleteFileById(selectedItem.getId().get());
        // dataSet.remove(selectedItem);
    }

    private void initializeTask(Task<Object> task, String prefix, Consumer<String> consumer) {
        task.setOnScheduled(e -> {
            consumer.accept("正在" + prefix + "，请稍后...");
        });
        task.setOnRunning(e -> {
            consumer.accept("开始" + prefix + "...");
        });
        task.setOnSucceeded(e -> {
            consumer.accept(prefix + "同步完成...");
        });
        task.exceptionProperty().addListener((observable, oldValue, newValue) -> {
            consumer.accept(newValue.getMessage());
        });
        SpringApp.getBean(ScheduledExecutorService.class).submit(task);
        consumer.accept("任务已创建...");
    }

    public void onUpdateEvaluationFormAction(ActionEvent event) {
        CompanyCustomerEvaluationFormUpdateTask task = new CompanyCustomerEvaluationFormUpdateTask();
        task.setCompanyService(getCompanyService());
        task.setCompanyCustomerFileService(getCompanyCustomerFileService());
        task.setCustomer(getCompanyCustomerService().findById(viewModel.getId().get()));
        UITools.showTaskDialogAndWait("更新评价表", task, consumer -> {
            initializeTask(task, "更新评价表", msg -> consumer.accept(Message.info(msg)));
        });
        loadTableDataSet();
    }

    public void onCalcNextSignDateAction(ActionEvent event) {
        UITools.showDialogAndWait("计算客户下一个评价日期", "依据已有的客户评估表和登记采购的合同计算下一个评估日期", ds -> {
            CompanyCustomer companyCustomer = getCompanyCustomerService().findById(viewModel.getId().get());
            LocalDate nextSignDate = getCompanyCustomerFileService().getNextSignDate(companyCustomer, (level, msg) -> {
                Platform.runLater(() -> {
                    ds.add(msg);
                });
            });
            if (nextSignDate != null) {
                Platform.runLater(() -> {
                    ds.add("下一个评价日期：" + nextSignDate);
                });
            }
        });
    }

    class FileTableFilePathTableCell extends TableCell<CompanyCustomerFileViewModel, String> {
        @Override
        protected void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);
            if (empty || !StringUtils.hasText(item)) {
                setText("");
                return;
            }

            String path = viewModel.getPath().get();
            if (StringUtils.hasText(path)) {
                if (item.startsWith(path)) {
                    item = "~" + item.substring(path.length());
                }
            }
            setText(item);
        }
    }

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

}
