package com.ecep.contract.controller.table.cell;

import java.util.Objects;
import java.util.concurrent.Future;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ecep.contract.Desktop;
import com.ecep.contract.model.BasedEntity;
import com.ecep.contract.model.IdentityEntity;
import com.ecep.contract.model.NamedEntity;
import com.ecep.contract.service.IEntityService;
import com.ecep.contract.util.ProxyUtils;

import javafx.application.Platform;

/**
 * 异步更新表格, 当单元格对应的数据未被初始化时, 显示#id, 当初始化后, 显示对应的文本
 *
 * @param <V>
 * @param <T>
 */
public class AsyncUpdateTableCell<V, K, T extends IdentityEntity> extends javafx.scene.control.TableCell<V, K> {
    private static final Logger logger = LoggerFactory.getLogger(AsyncUpdateTableCell.class);

    /**
     * 转换为文本
     */
    public static String toString(Object entity) {
        if (entity instanceof NamedEntity named) {
            return named.getName();
        }
        if (entity instanceof BasedEntity e) {
            return e.toPrettyString();
        }
        return entity.toString();
    }

    private IEntityService<T> service;
    Future<?> syncFuture;

    /**
     * 通过 #setService 设置服务类，或者子类实现, 提供服务类
     *
     * @return
     */
    protected IEntityService<T> getServiceBean() {
        return null;
    }

    public String format(T entity) {
        return toString(entity);
    }

    public void setService(IEntityService<T> service) {
        this.service = service;
    }

    public IEntityService<T> getService() {
        if (service == null) {
            service = getServiceBean();
        }
        return service;
    }

    @Override
    protected void updateItem(K itemId, boolean empty) {
        super.updateItem(itemId, empty);
        // 取消之前的异步任务
        if (syncFuture != null) {
            syncFuture.cancel(true);
            syncFuture = null;
        }

        if (empty || itemId == null) {
            setText(null);
            return;
        }
        // if (isInitialized(itemId)) {
        // setText(format(itemId));
        // return;
        // }

        setText("# " + itemId);
        syncFuture = submit(this::asyncLoadAndUpdate);
    }

    /**
     * 检查实体是否已初始化
     *
     * @param proxy
     * @return
     */
    protected boolean isInitialized(T proxy) {
        return ProxyUtils.isInitialized(proxy);
    }

    /**
     * 初始化实体
     *
     * @return
     */
    protected T initialize() {
        K k = getItem();
        if (k == null) {
            return null;
        }
        if (k instanceof Integer id) {
            return getService().findById(id);
        }
        throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     * 提交异步任务
     *
     * @param var1 异步任务
     * @return
     */
    Future<?> submit(Runnable var1) {
        return Desktop.instance.getExecutorService().submit(var1);
    }

    protected void asyncLoadAndUpdate() {
        if (getItem() == null) {
            return;
        }

        // if (getService() instanceof QueryService<T, ?> queryService) {
        // queryService.findById(getItem().getId());
        // queryService.asyncFindById(getItem().getId()).thenAccept(this::_updateEntity);
        // return;
        // }
        T entity = initialize();
        _updateEntity(entity);

    }

    private void _updateEntity(T entity) {
        String formated;
        try {
            formated = format(entity);
        } catch (Exception e) {
            formated = e.getMessage();
        }
        String texted = formated;

        // 保存当前需要更新的项目信息，避免闭包引用导致的问题
        final T updatedEntity = entity;
        final String updatedText = texted;
        final K finalCurrentLoadingItem = getItem();

        Platform.runLater(() -> {
            // 检查单元格是否仍然显示相同的项目
            // 如果单元格已被重用或当前项目已改变，则不更新
            if (isEmpty() || getItem() == null) {
                return;
            }

            if (!Objects.equals(getItem(), finalCurrentLoadingItem)) {
                logger.debug("Skipping async update - cell item changed");
                return;
            }
            setText(updatedText);
        });
    }

}
