package com.ss.editor.ui.component.asset.tree;

import static com.ss.editor.manager.FileIconManager.DEFAULT_FILE_ICON_SIZE;
import static java.util.Collections.singletonList;
import com.ss.editor.annotation.FxThread;
import com.ss.editor.manager.FileIconManager;
import com.ss.editor.ui.FxConstants;
import com.ss.editor.ui.component.asset.tree.resource.FolderResourceElement;
import com.ss.editor.ui.component.asset.tree.resource.LoadingResourceElement;
import com.ss.editor.ui.component.asset.tree.resource.ResourceElement;
import com.ss.rlib.common.util.StringUtils;
import javafx.geometry.Side;
import javafx.scene.Cursor;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.Tooltip;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeView;
import javafx.scene.image.ImageView;
import javafx.scene.input.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.nio.file.Files;

/**
 * The implementation of the cell for {@link TreeView} to show resource.
 *
 * @author JavaSaBr
 */
public class ResourceTreeCell extends TreeCell<ResourceElement> {

    /**
     * The file icon manager.
     */
    @NotNull
    private static final FileIconManager ICON_MANAGER = FileIconManager.getInstance();

    /**
     * The icon.
     */
    @NotNull
    private final ImageView icon;

    /**
     * The tooltip of this resource.
     */
    @Nullable
    private Tooltip tooltip;

    protected ResourceTreeCell() {
        setOnMouseClicked(this::handleMouseClickedEvent);
        setOnDragDetected(this::handleStartDragEvent);
        setOnDragDone(this::handleStopDragEvent);
        this.icon = new ImageView();
        this.tooltip = new Tooltip();
    }

    /**
     * Handle stop drag events.
     *
     * @param event the stop drag event.
     */
    @FxThread
    private void handleStopDragEvent(@NotNull DragEvent event) {
        setCursor(Cursor.DEFAULT);
        event.consume();
    }

    /**
     * Handle start drag events.
     *
     * @param mouseEvent the mouse event.
     */
    @FxThread
    private void handleStartDragEvent(@NotNull MouseEvent mouseEvent) {
        startFullDrag();

        var item = getItem();
        if (item == null) {
            return;
        }

        var file = item.getFile();
        if (!Files.exists(file)) {
            return;
        }

        var dragBoard = startDragAndDrop(TransferMode.COPY);
        var content = new ClipboardContent();
        content.put(DataFormat.FILES, singletonList(file.toFile()));

        dragBoard.setContent(content);

        setCursor(Cursor.MOVE);
        mouseEvent.consume();
    }

    /**
     * Handle mouse clicked events.
     *
     * @param event the mouse clicked event.
     */
    @FxThread
    private void handleMouseClickedEvent(@NotNull MouseEvent event) {

        var item = getItem();
        if (item == null) {
            return;
        }

        var isFolder = item instanceof FolderResourceElement;
        var treeView = (ResourceTree) getTreeView();

        if (event.getButton() == MouseButton.SECONDARY) {

            var contextMenu = treeView.getContextMenu(item);
            if (contextMenu == null) {
                return;
            }

            contextMenu.show(this, Side.BOTTOM, 0, 0);

        } else if ((treeView.isOnlyFolders() || !isFolder) &&
                event.getButton() == MouseButton.PRIMARY && event.getClickCount() > 1) {

            var openFunction = treeView.getOpenFunction();
            if (openFunction != null) {
                openFunction.accept(item);
            }
        }
    }

    @Override
    @FxThread
    protected void updateItem(@Nullable ResourceElement item, boolean empty) {
        super.updateItem(item, empty);

        removeToolTip();

        if (item == null) {
            setText(StringUtils.EMPTY);
            setGraphic(null);
            return;
        } else if (item instanceof LoadingResourceElement) {
            setText("Loading...");
            setGraphic(createIndicator());
            return;
        }

        var file = item.getFile();
        var fileName = file.getFileName();
        var folder = item instanceof FolderResourceElement;

        icon.setImage(ICON_MANAGER.getIcon(file, folder, true, DEFAULT_FILE_ICON_SIZE));

        setText(fileName == null ? file.toString() : fileName.toString());
        setGraphic(icon);
        createToolTip();
    }

    @FxThread
    private @NotNull ProgressIndicator createIndicator() {
        var indicator = new ProgressIndicator();
        indicator.setMaxHeight(FxConstants.RESOURCE_TREE_CELL_HEIGHT - 2);
        indicator.setMaxWidth(FxConstants.RESOURCE_TREE_CELL_HEIGHT - 2);
        return indicator;
    }

    @FxThread
    private void removeToolTip() {
        if (tooltip == null) return;
        Tooltip.uninstall(this, tooltip);
        tooltip = null;
    }

    @FxThread
    private void createToolTip() {
        tooltip = getItem().createToolTip();
        if (tooltip == null) return;
        Tooltip.install(this, tooltip);
    }
}