package com.ecep.contract.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

import com.ecep.contract.controller.table.EditableEntityTableTabSkin;
import com.ecep.contract.controller.table.TableTabSkin;
import com.ecep.contract.model.IdentityEntity;
import com.ecep.contract.service.ViewModelService;
import com.ecep.contract.util.TableViewUtils;
import com.ecep.contract.util.UITools;
import com.ecep.contract.vm.IdentityViewModel;

import javafx.application.Platform;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.util.converter.NumberStringConverter;

/**
 * 实体管理器皮肤
 * 提供了实体管理器的基本功能，如查询、新增、删除、修改、分页等
 * 
 * @param <T>    Entity 的类型
 * @param <TV>   Entity 对应的ViewModel
 * @param <SKIN> Skin 的类型
 * @param <C>
 */
public abstract class AbstEntityManagerSkin<T extends IdentityEntity, TV extends IdentityViewModel<T>, SKIN extends ManagerSkin, C extends AbstManagerWindowController<T, TV, SKIN>>
        implements ManagerSkin, TableTabSkin<T, TV>, EditableEntityTableTabSkin<T, TV> {
    private static final Logger logger = LoggerFactory.getLogger(AbstEntityManagerSkin.class);
    /**
     *
     */
    protected C controller;

    protected CompletableFuture<Void> loadedFuture;
    protected ObservableList<TV> dataSet = FXCollections.observableArrayList();

    protected PageRequest currentPageable = PageRequest.ofSize(25);
    protected final SimpleIntegerProperty currentPageNumber = new SimpleIntegerProperty();
    // 是否允许调整表格高度
    private boolean allowResize = true;
    // 记录延时任务信息
    private ScheduledFuture<?> loadTableDataSetFuture;

    public AbstEntityManagerSkin(C controller) {
        this.controller = controller;
    }

    @Override
    public <TT> TT getBean(Class<TT> requiredType) throws BeansException {
        return controller.getCachedBean(requiredType);
    }

    @Override
    public TableView<TV> getTableView() {
        return controller.table;
    }

    @Override
    public void handleException(String message, Throwable ex) {
        if (controller != null) {
            controller.handleException(message, ex);
            return;
        }

        if (logger.isErrorEnabled()) {
            logger.error(message, ex);
        }
        UITools.showExceptionAndWait(message, ex);
    }

    public Locale getLocale() {
        return controller.getLocale();
    }

    public void install() {
        onShown();

        // 注册 F5 和 Ctrl+R 刷新快捷键
        KeyCodeCombination ctrlRCombination = new KeyCodeCombination(KeyCode.R, KeyCombination.SHORTCUT_DOWN);
        KeyCodeCombination f5Combination = new KeyCodeCombination(KeyCode.F5);
        getTableView().addEventHandler(KeyEvent.KEY_PRESSED, event -> {
            if (ctrlRCombination.match(event) || f5Combination.match(event)) {
                System.out.println("loadTableDataSetFuture = " + loadTableDataSetFuture);
                if (loadTableDataSetFuture == null) {
                    loadTableDataSet(false);
                }
                event.consume();
            }
        });
    }

    private void onShown() {
        if (loadedFuture == null) {
            loadedFuture = runAsync(() -> {
                Platform.runLater(() -> {
                    getTableView().setItems(dataSet);
                });
                initializeSearchBar();
                initializeTable();
                initializeFooter();
                TableView<TV> table = getTableView();
                // 视图更新时
                table.layoutBoundsProperty().addListener(this::resizeTable);

                // 启用行编辑功能
                if (!table.isEditable()) {
                    TableViewUtils.bindDoubleClicked(table, this::onTableRowDoubleClickedAction);
                }

                if (table.contextMenuProperty().get() == null) {
                    ContextMenu contextMenu = new ContextMenu();
                    createContextMenu(contextMenu);
                    table.setContextMenu(contextMenu);
                }

                table.setSortPolicy(v -> {
                    if (loadTableDataSetFuture == null) {
                        loadTableDataSet(false);
                    }
                    return true;
                });

                loadTableDataSet(true);
            });
        }
    }

    private void initializeSearchBar() {
        if (controller.searchKeyField != null) {
            controller.searchKeyField.setOnKeyReleased(event -> {
                if (event.getCode() == KeyCode.ENTER) {
                    controller.searchBtn.fire();
                }
            });
        }
        if (controller.searchBtn != null) {
            controller.searchBtn.setOnAction(this::onSearchAction);
        }
    }

    private void initializeFooter() {
        currentPageNumber.addListener(this::currentPageNumberListener);

        //
        controller.currentPageNumberField.textProperty().bindBidirectional(currentPageNumber,
                new NumberStringConverter());
        controller.previousPageBtn.setOnAction(event -> {
            try {
                currentPageable = currentPageable.previous();
                loadTableDataSet(true);
            } catch (Exception e) {
                logger.warn("previous page error", e);
            }
        });
        controller.nextPageBtn.setOnAction(event -> {
            try {
                currentPageable = currentPageable.next();
                loadTableDataSet(true);
            } catch (Exception e) {
                logger.warn("next page error", e);
            }
        });
    }

    private void currentPageNumberListener(Object obj, Number old, Number newValue) {
        int page = newValue.intValue();
        if (page < 0) {
            page = 0;
        }
        if (currentPageable.getPageNumber() == page) {
            return;
        }
        currentPageable = currentPageable.withPage(page);
        loadTableDataSet(false);
    }

    public void onSearchAction(ActionEvent event) {
        currentPageable = currentPageable.withPage(0);
        loadTableDataSet(true);
    }

    /**
     * 根据表格高度重新计算分页的页大小
     */
    private void resizeTable(Object observable, Bounds old, Bounds newBounds) {
        if (!allowResize) {
            return;
        }
        double tableHeight = newBounds.getHeight();
        if (tableHeight <= 0) {
            return;
        }
        TableView<TV> table = getTableView();
        Node lookup = table.lookup("TableRow");
        if (lookup != null) {
            double rowHeight = lookup.prefHeight(-1);
            int rows = (int) Math.round(table.getHeight() / rowHeight) - 1;
            // 只有当行数变化超过一定阈值时才重新加载数据
            int currentRows = currentPageable.getPageSize();
            if (Math.abs(rows - currentRows) <= 2) {
                return; // 避免微小变化导致频繁刷新
            }

            int pageNumber = (int) Math.abs(currentPageable.getOffset() / rows);
            if (currentPageable.getPageNumber() == pageNumber && currentPageable.getPageSize() == rows) {
                return;
            }
            currentPageable = PageRequest.of(pageNumber, rows);
            loadTableDataSet(false);
        }
    }

    protected void createContextMenu(ContextMenu contextMenu) {
        MenuItem item2 = new MenuItem("刷新");
        item2.setOnAction(this::onTableRefreshAction);

        contextMenu.getItems().add(item2);

        if (this instanceof EditableEntityTableTabSkin) {
            MenuItem item1 = new MenuItem("新建");
            item1.setOnAction(this::onTableCreateNewAction);

            MenuItem item3 = new MenuItem("删除");
            item3.setOnAction(this::onTableDeleteAction);

            contextMenu.getItems().addAll(item1, item3);
        }
    }

    protected void onTableCreateNewAction(ActionEvent event) {
        TV viewModel = createNewViewModel();
        dataSet.add(viewModel);
    }

    protected void onTableRefreshAction(ActionEvent event) {
        loadTableDataSet(false);
    }

    protected void onTableDeleteAction(ActionEvent event) {
        ObservableList<TV> selectedItems = getTableView().getSelectionModel().getSelectedItems();
        if (selectedItems.isEmpty()) {
            return;
        }
        if (!UITools.showConfirmDialog("删除行", "确认删除选中的" + selectedItems.size() + "条数据？")) {
            return;
        }
        for (TV selectedItem : new ArrayList<>(selectedItems)) {
            if (deleteRow(selectedItem)) {
                dataSet.remove(selectedItem);
            }
        }
    }

    /**
     * 处理单元格编辑事件
     * 
     * @param <K>
     * @param event
     * @param propGetter
     */
    protected <K> void acceptCellEditEvent(TableColumn.CellEditEvent<TV, K> event,
            Function<TV, Property<K>> propGetter) {
        TV row = event.getRowValue();
        Property<K> property = propGetter.apply(row);
        property.setValue(event.getNewValue());
        try {
            saveRowData(row);
        } catch (Exception e) {
            handleException("保存出错", e);
        }
    }

    protected boolean deleteRow(TV row) {
        ViewModelService<T, TV> service = getViewModelService();
        T entity = service.findById(row.getId().get());
        if (entity != null) {
            try {
                service.delete(entity);
                return true;
            } catch (UnsupportedOperationException e) {
                handleException("删除出错，此操作不支持", e);
            } catch (Exception e) {
                handleException("删除出错", e);
            }
        }
        return false;
    }

    protected T createNewEntity(TV row) {
        ViewModelService<T, TV> service = getViewModelService();
        if (service != null) {
            T entity = service.createNewEntity();
            if (entity != null) {
                return entity;
            }
        }
        return null;
    }

    protected TV createNewViewModel() {
        ViewModelService<T, TV> service = getViewModelService();
        if (service != null) {
            TV model = service.createNewViewModel();
            if (model != null) {
                return model;
            }
        }
        return null;
    }

    protected void saveRowData(TV row) {
        ViewModelService<T, TV> service = getViewModelService();
        if (service == null) {
            handleException("ViewModelService is null", new RuntimeException());
            return;
        }
        row.saveInFxApplicationThread(service);
    }

    /**
     * 加载行数据
     * 
     * @param row
     * @return
     */
    public T loadRowData(TV row) {
        if (row.getId() == null) {
            return null;
        }
        T entity = getViewModelService().findById(row.getId().get());
        return entity;
    }

    /**
     * 删除行数据
     * 
     * @param entity
     */
    public void deleteRowData(T entity) {
        if (entity == null) {
            return;
        }
        ViewModelService<T, TV> service = getViewModelService();
        getViewModelService().delete(entity);
    }

    /**
     * 保存行数据
     * 
     * @param entity
     * @return
     */
    public T saveRowData(T entity) {
        if (entity == null) {
            return null;
        }
        ViewModelService<T, TV> service = getViewModelService();
        return getViewModelService().save(entity);
    }

    @Override
    public void loadTableDataSet() {
        loadTableDataSet(false);
    }

    /**
     * 加载表格数据
     * 延时任务未执行前，再次调用此函数时，重新延时
     *
     * @param reloadNow 是否立即刷新，立即刷新将直接submit一个任务到 Executor，否则 schedule 一个618毫秒的延时任务
     */
    public void loadTableDataSet(boolean reloadNow) {
        if (loadTableDataSetFuture != null) {
            loadTableDataSetFuture.cancel(true);
        }
        loadTableDataSetFuture = getExecutorService().schedule(() -> {
            try {
                _reloadTableData().thenRun(() -> loadTableDataSetFuture = null).exceptionally(this::handleException);
            } catch (Exception ex) {
                handleException("加载表格数据出错", ex);
            }
        }, reloadNow ? 0 : 618, TimeUnit.MILLISECONDS);
    }

    private CompletableFuture<Void> _reloadTableData() {
        CompletableFuture<Void> future = new CompletableFuture<>();
        Platform.runLater(() -> {
            allowResize = false; // 禁用调整
            dataSet.clear();
            runAsync(() -> {
                controller.setStatus("载入中...");
                List<TV> models = loadTableData();
                Platform.runLater(() -> {
                    try {
                        updateTableDataSet(models);
                        allowResize = true; // 恢复调整
                        future.complete(null);
                    } catch (Exception e) {
                        allowResize = true; // 恢复调整
                        future.completeExceptionally(e);
                    }
                });
            }).exceptionally(ex -> {
                future.completeExceptionally(ex);
                return null;
            });
        });
        return future;
    }

    /**
     * 更新表格数据
     * 
     * @param models
     */
    protected void updateTableDataSet(List<TV> models) {
        long timeMillis = System.currentTimeMillis();
        // 清除所有选择状态，避免选择状态混乱
        if (getTableView() != null && getTableView().getSelectionModel() != null) {
            getTableView().getSelectionModel().clearSelection();
        }

        // 先清空再设置新数据，避免数据叠加
        dataSet.clear();
        if (models != null) {
            dataSet.addAll(models);
        }

        // 强制刷新表格布局
        if (getTableView() != null) {
            getTableView().requestLayout();
            getTableView().refresh();
        }

        long timeCost = System.currentTimeMillis() - timeMillis;
        if (logger.isDebugEnabled()) {
            logger.debug("update table dataSet cost: {} ms", timeCost);
        }
    }

    /**
     * 加载表格数据
     * 
     * @return
     */
    protected List<TV> loadTableData() {
        Map<String, Object> params = getSpecification();
        ViewModelService<T, TV> service = getViewModelService();
        long timeMillis = System.currentTimeMillis();
        Page<T> page = service.findAll(params, getPageable());
        long timeCost = System.currentTimeMillis() - timeMillis;
        if (logger.isDebugEnabled()) {
            logger.debug("load table data cost: {} ms", timeCost);
        }
        if (timeCost > 1000) {
            controller.setStatus("used " + timeCost + " ms");
        }
        updateFooter(page);
        return page.map(service::from).toList();
    }

    /**
     * 获取ViewModelService
     * 
     * @return
     */
    protected ViewModelService<T, TV> getViewModelService() {
        ViewModelService<T, TV> service = controller.getViewModelService();
        if (service == null) {
            throw new IllegalArgumentException("ViewModelService is null");
        }
        return service;
    }

    /**
     * 获取查询条件
     * 
     * @return
     */
    public Map<String, Object> getSpecification() {
        TextField field = controller.searchKeyField;
        if (field != null) {
            return getViewModelService().getSpecification(field.getText());
        }
        return null;
    }

    /**
     * 获取查询条件
     * 
     * @param searchText
     * @return
     */
    protected Map<String, Object> getSpecification(String searchText) {
        return getViewModelService().getSpecification(searchText);
    }

    /**
     * 当表格行被双击时触发
     *
     * @param item 被双击的行数据
     */
    protected void onTableRowDoubleClickedAction(TV item) {
    }

    /**
     * 更新页脚
     * 
     * @param page
     */
    protected void updateFooter(Page<T> page) {
        Platform.runLater(() -> {
            controller.previousPageBtn.setDisable(!page.hasPrevious());
            controller.nextPageBtn.setDisable(!page.hasNext());
            currentPageNumber.set(page.getNumber());
            controller.setStatus(
                    (page.getNumber() + 1) + "/" + page.getTotalPages() + " 页, 总 " + page.getTotalElements() + " 条");
        });
    }

    /**
     * 获取表格排序
     * 
     * @return
     */
    public List<Sort.Order> getTableOrders() {
        return TableViewUtils.getOrders(getTableView());
    }

    /**
     * 获取表格排序
     * 
     * @return
     */
    public Sort getSortByTable() {
        if (getTableView() == null) {
            return Sort.unsorted();
        }
        return Sort.by(getTableOrders());
    }

    /**
     * 获取分页参数
     * 
     * @return
     */
    public Pageable getPageable() {
        Sort sort = getSortByTable();
        return currentPageable.withSort(sort);
    }

    /**
     * 显示在当前窗口为父窗口的新窗口
     * 
     * @param <Controller> 控制器类型
     * @param clz          控制器类
     * @param model        数据
     */
    protected <Controller extends AbstEntityController<T, TV>> void showInOwner(Class<Controller> clz, TV model) {
        BaseController.show(clz, model, getTableView().getScene().getWindow());
    }
}
