import { App, Avatar } from "antd";
import $ from "jquery";
import { reaction, toJS } from "mobx";
import { Observer, observer } from "mobx-react";
import { useCallback, useEffect, useRef, useState } from "react";

import type { CreatableProps, ToolbarButtonProps, TreeNodeProps, TreeProps } from "@devowl-wp/react-folder-tree";
import { Alert, Icon, Tree, immer, message } from "@devowl-wp/react-folder-tree";
import { useWindowSize } from "@devowl-wp/react-utils";
import { Provider as LicenseProvider } from "@devowl-wp/real-product-manager-wp-client";
import { RatingPointer } from "@devowl-wp/real-utils";

import { DashIcon } from "./dashIcon.js";
import { ConfigLicensingConsumer } from "./licensing/consumer.js";
import { ProFooter } from "./proFooter.js";
import { Provider } from "./provider.js";
import { TaxSwitcher } from "./taxSwitcher.js";
import { useHandleSelect } from "../hooks/appTree/useHandleSelect.js";
import { usePaginationFastMode } from "../hooks/appTree/usePaginationFastMode.js";
import { usePostDraggable } from "../hooks/appTree/usePostDraggable.js";
import { usePostDroppable } from "../hooks/appTree/usePostDroppable.js";
import { useRenameNode } from "../hooks/appTree/useRenameNode.js";
import { useSortMode } from "../hooks/appTree/useSortMode.js";
import { useTrashNode } from "../hooks/appTree/useTrashNode.js";
import { useStores } from "../store/stores.js";
import { TreeStore } from "../store/tree.js";
import { __, _i } from "../utils/i18n.js";

const DEFAULT_CREATABLE_CLASSES = "page-title-action add-new-h2";

message.config({
    top: 50,
});

/**
 * The application tree handler for Real Category Management.
 */
const AppTree = observer(() => {
    const { modal } = App.useApp();
    const { treeStore, optionStore } = useStores();
    const { tree, staticTree, selectedId, createRoot } = treeStore;
    const { busySettings, publicUrl, others } = optionStore;
    const {
        isDevLicense,
        pluginRcpo: { active: rcpoActive },
        typenow,
        taxnow,
        taxos,
        blogId,
        showLiteNotice,
        isPro,
        showProHints,
        sortableTaxos,
    } = others;
    const id = `rcl-${blogId}`; // DOM element id for the complete tree
    const mobile = useWindowSize().width < 700;
    const { isOrderModeActive, handleOrderModifier, handleOrderClick, handleOrderCancel } = useSortMode();

    // States
    const [isSticky, setIsSticky] = useState(!mobile);
    const [isStickyHeader, setIsStickyHeader] = useState(!mobile);
    const [isResizable, setIsResizable] = useState(!mobile);
    const [isFullWidth, setIsFullWidth] = useState(!mobile);
    const [style, setStyle] = useState(mobile ? { marginLeft: 10 } : {});
    const [isToolbarActive, setIsToolbarActive] = useState(true);
    const [isToolbarBusy, setIsToolbarBusy] = useState(false);
    const [isSortableDisabled, setIsSortableDisabled] = useState(true);
    const [isSortableBusy, setIsSortableBusy] = useState(false);
    const [isCreatableLinkDisabled, setIsCreatableLinkDisabled] = useState(false);
    const [isCreatableLinkCancel, setIsCreatableLinkCancel] = useState(false);
    const [isTreeLinkDisabled, setIsTreeLinkDisabled] = useState(false);
    const [toolbarActiveButton, setToolbarActiveButton] = useState(isOrderModeActive ? "order" : undefined);
    const isSortable = sortableTaxos[taxnow];

    const makeDraggable = usePostDraggable(isOrderModeActive);
    const handleSelect = useHandleSelect(toolbarActiveButton, isOrderModeActive, makeDraggable);
    const makeDroppable = usePostDroppable(id, makeDraggable);
    const { handleRenameClick, handleRenameCancel, handleNodePressF2, handleRenameClose } = useRenameNode(
        setIsCreatableLinkDisabled,
        setIsTreeLinkDisabled,
        setToolbarActiveButton,
    );
    const { handleTrashModifier } = useTrashNode(handleSelect);
    usePaginationFastMode(makeDraggable);

    /**
     * A node item must be an observer.
     */
    const handleTreeNodeRender: TreeNodeProps["renderItem"] = useCallback(
        (createTreeNode, TreeNodeS, node) => <Observer key={node.id}>{() => createTreeNode(node)}</Observer>,
        [],
    );

    /**
     * MobX states should only hold serialized data so use strings for icons
     * and render it manually.
     */
    const handleRenderIcon: TreeNodeProps["renderIcon"] = useCallback((icon) => <Icon type={icon} />, []);

    // Responsiveness
    useEffect(() => {
        $(window).resize(() => {
            const rmobile = window.innerWidth < 700;
            setIsSticky(!rmobile);
            setIsStickyHeader(!rmobile);
            setIsResizable(!rmobile);
            setIsFullWidth(rmobile);
            setStyle(rmobile ? { marginLeft: 10 } : {});
        });
    }, []);

    useEffect(() => {
        // Show license dialog for the first time
        if (others.showLicenseFormImmediate && !(window as any).Playwright) {
            const createdModal = modal.info({
                icon: null,
                title: (
                    <>
                        <span>Real Category Management</span>
                        <Provider app={{ style: { float: "right" } }}>
                            <Avatar
                                src={`${publicUrl}images/logos/real-category-library.svg`}
                                shape="square"
                                size={30}
                            />
                        </Provider>
                    </>
                ),
                width: 800,
                okButtonProps: {
                    style: { display: "none" },
                },
                cancelButtonProps: {
                    style: { display: "none" },
                },
                maskClosable: false,
                content: (
                    <LicenseProvider>
                        <ConfigLicensingConsumer withinModal />
                    </LicenseProvider>
                ),
            });

            // Automatically close the dialog
            reaction(
                () => others.showLicenseFormImmediate,
                (val) => {
                    if (!val) {
                        createdModal.destroy();
                    }
                },
            );
        }
    }, []);

    /**
     * Reload the current view (hard page reload).
     */
    const handleReload: ToolbarButtonProps["onClick"] = useCallback(() => window.location.reload(), []);

    /**
     * Handles the creatable click and creates a new node depending on the selected one.
     */
    const handleCreatable = useCallback(
        (type?: CreatableProps["type"]) => {
            let shCreateRoot: TreeNodeProps;
            let $create: any;

            if (type) {
                // Activate create
                const newNode: TreeNodeProps = {
                    $rename: true,
                    $busy: false,
                    icon: "folder-open",
                };
                if (treeStore.selectedId === TreeStore.ID_ALL) {
                    shCreateRoot = newNode;
                } else {
                    $create = newNode;
                    $create.parent = treeStore.selectedId;
                }
            }

            setIsTreeLinkDisabled(!!type);
            setIsCreatableLinkCancel(!!type);
            setIsToolbarActive(!type);
            treeStore.setCreateRoot(shCreateRoot);
            treeStore.selected.setCreate($create);
        },
        [treeStore, setIsTreeLinkDisabled, setIsCreatableLinkCancel, setIsToolbarActive],
    );

    const handleCreatableClick: CreatableProps["onClick"] = useCallback(
        (type) => handleCreatable(type),
        [handleCreatable],
    );
    const handleCreatableCancel: CreatableProps["onClick"] = useCallback(() => handleCreatable(), [handleCreatable]);

    /**
     * Updates the create node. That's the node without id and the input field.
     */
    const updateCreateNode = useCallback(
        (callback: (node: typeof createRoot) => void) => {
            treeStore.createRoot && treeStore.setCreateRoot(immer.produce(toJS(treeStore.createRoot as any), callback));
            const { selected } = treeStore;
            selected?.$create && selected.setCreate(immer.produce(toJS(selected.$create as any), callback));
        },
        [treeStore, createRoot],
    );

    /**
     * Handle add close and remove the new node.
     */
    const handleAddClose: TreeNodeProps["onAddClose"] = useCallback(
        async (save, name, node) => {
            const parent = +((node as any).parent || 0);
            if (save) {
                updateCreateNode((shNode) => {
                    shNode.$busy = true;
                });
                const hide = message.loading(__('Creating "%s"...', name));
                try {
                    await treeStore.persist({
                        name,
                        parent,
                        type: typenow,
                        taxonomy: taxnow,
                    });
                    handleCreatableCancel(undefined);

                    // Show rating pointer
                    const { isRatable, slug } = optionStore;
                    isRatable && new RatingPointer(slug, $(".aiot-tree-headline"));

                    message.success(__('"%s" successfully created.', name));
                    makeDroppable();
                } catch (e) {
                    message.error(e.responseJSON.message);
                } finally {
                    updateCreateNode((shNode) => {
                        shNode.$busy = false;
                    });
                    hide();
                }
            } else {
                handleCreatableCancel(undefined);
            }
        },
        [treeStore, optionStore, typenow, taxnow, handleCreatableCancel, makeDroppable, updateCreateNode],
    );

    /**
     * Handle the sort toolbar button to activate the sortable tree.
     */
    const handleSortNode = useCallback(
        (shToolbarActiveButton?: typeof toolbarActiveButton, isBusy?: boolean) => {
            setIsCreatableLinkDisabled(!!shToolbarActiveButton);
            setToolbarActiveButton(shToolbarActiveButton);
            setIsSortableDisabled(!shToolbarActiveButton);
            typeof isBusy === "boolean" && setIsSortableBusy(isBusy);
            typeof isBusy === "boolean" && setIsToolbarBusy(isBusy);
        },
        [
            setIsCreatableLinkDisabled,
            setToolbarActiveButton,
            setIsSortableDisabled,
            setIsSortableBusy,
            setIsToolbarBusy,
        ],
    );

    const handleSortClick: ToolbarButtonProps["onClick"] = useCallback(() => handleSortNode("sort"), [handleSortNode]);
    const handleSortCancel: ToolbarButtonProps["onCancel"] = useCallback(() => handleSortNode(), [handleSortNode]);

    /**
     * Handle categories sorting and update the tree so the changes are visible. If sorting
     * is cancelled the old tree gets restored.
     */
    const handleSort: TreeProps["onSort"] = useCallback(
        async ({ id, oldIndex, newIndex, parentFromId, parentToId, nextId }) => {
            setIsSortableBusy(true);
            setIsToolbarBusy(true);

            const hide = message.loading(__("Category tree will be reordered soon..."));
            try {
                await treeStore.sort({
                    id: +id,
                    oldIndex,
                    newIndex,
                    parentFromId: +parentFromId,
                    parentToId: +parentToId,
                    nextId: +nextId,
                    request: true,
                });
                message.success(__("Category tree is successfully reordered."));
            } catch (e) {
                message.error((e as any).responseJSON.message);
            } finally {
                hide();
                handleSortNode(toolbarActiveButton, false);
            }
        },
        [treeStore, setIsSortableBusy, setIsToolbarBusy, handleSortNode, toolbarActiveButton],
    );

    /**
     * Navigate to category details.
     */
    const handleDetails: ToolbarButtonProps["onClick"] = useCallback(() => {
        window.open(`term.php?taxonomy=${taxnow}&tag_ID=${treeStore.selectedId}&post_type=${typenow}`, "_blank");
    }, [treeStore, typenow, taxnow]);

    const delayedDroppableTimeout = useRef<ReturnType<typeof setTimeout>>();
    const handleDelayedDroppable = useCallback(() => {
        clearTimeout(delayedDroppableTimeout.current);
        delayedDroppableTimeout.current = setTimeout(makeDroppable, 200);
    }, [makeDraggable, delayedDroppableTimeout]);

    // Rendering process
    const treeProps = {
        staticTree,
        tree,
        id,
        createRoot,
        isSticky,
        isStickyHeader,
        isResizable,
        isFullWidth,
        style,
        isToolbarActive,
        isToolbarBusy: isToolbarBusy || busySettings,
        isSortable,
        isSortableDisabled: false,
        sortableDelay: isSortableDisabled ? 150 : 0,
        isSortableBusy,
        isTreeBusy: treeStore.busy,
        isCreatableLinkDisabled,
        isCreatableLinkCancel,
        isTreeLinkDisabled,
        toolbarActiveButton,
    };
    return (
        <Tree
            {...treeProps}
            onSelect={handleSelect}
            headline={<span style={{ paddingRight: 5 }}>{__("Categories")}</span>}
            opposite={document.getElementById("wpbody-content")}
            attr={{ "data-type": typenow, "data-tax": taxnow }}
            renameSaveText={<Icon type="save" />}
            renameAddText={<Icon type="save" />}
            noFoldersTitle={__("No category found")}
            noFoldersDescription={__("Click the button above to create a new category.")}
            noSearchResult={__("No search results found")}
            innerClassName="wrap"
            theme="wordpress"
            headerStickyAttr={{
                top: "#wpadminbar",
            }}
            renderItem={handleTreeNodeRender}
            renderIcon={handleRenderIcon}
            onNodePressF2={handleNodePressF2}
            onRenameClose={handleRenameClose}
            onAddClose={handleAddClose}
            onNodeExpand={handleDelayedDroppable}
            onSearchResult={handleDelayedDroppable}
            onSort={handleSort}
            creatable={{
                backButton: {
                    cssClasses: DEFAULT_CREATABLE_CLASSES,
                    label: __("Cancel"),
                    onClick: handleCreatableCancel,
                },
                buttons: {
                    folder: {
                        icon: <Icon type="folder-add" />,
                        cssClasses: DEFAULT_CREATABLE_CLASSES,
                        toolTipTitle: __("Click this to create a new category"),
                        toolTipText: __(
                            "To create a subcategory, simply select a category from the list and click this button.",
                        ),
                        label: __("New"),
                        onClick: handleCreatableClick,
                    },
                },
            }}
            toolbar={{
                backButton: {
                    label: isOrderModeActive || toolbarActiveButton === "sort" ? __("Back") : __("Cancel"),
                    save: __("Save"),
                },
                buttons: {
                    order: !rcpoActive && {
                        content: <DashIcon name="move" />,
                        toolTipTitle: __("Reorder entries"),
                        toolTipText: _i(
                            __(
                                "Start to reorder the entries with the help of the free plugin {{strong}}Real Custom Post Order{{/strong}}.",
                            ),
                            {
                                strong: <strong />,
                            },
                        ),
                        modifier: handleOrderModifier,
                        onClick: handleOrderClick,
                        onCancel: handleOrderCancel,
                    },
                    reload: {
                        content: <Icon type="reload" />,
                        toolTipTitle: __("Refresh"),
                        toolTipText: __("Refreshes the category view."),
                        onClick: handleReload,
                    },
                    rename: {
                        content: <Icon type="edit" />,
                        toolTipTitle: __("Rename"),
                        toolTipText: __("Rename the currently selected category."),
                        disabled: selectedId === TreeStore.ID_ALL,
                        onClick: handleRenameClick,
                        onCancel: handleRenameCancel,
                    },
                    trash: {
                        content: <Icon type="delete" />,
                        toolTipTitle: __("Delete"),
                        toolTipText: __("Delete the currently selected category."),
                        disabled: selectedId === TreeStore.ID_ALL,
                        modifier: handleTrashModifier,
                    },
                    sort: {
                        content: <DashIcon name="sort" />,
                        toolTipTitle: __("Rearrange"),
                        toolTipText: __("Change the hierarchical order of the categories."),
                        onClick: handleSortClick,
                        onCancel: handleSortCancel,
                        visible: isSortable,
                    },
                    details: {
                        content: <Icon type="ellipsis" />,
                        toolTipTitle: __("View and edit category"),
                        toolTipText: __("Select a category and see more details about it or edit it."),
                        disabled: selectedId === TreeStore.ID_ALL,
                        onClick: handleDetails,
                    },
                },
            }}
            forceSortableFallback
        >
            {isDevLicense && (
                <Alert
                    message={
                        <>
                            {__("Product license not for production use!")} (
                            <a
                                href={__("https://devowl.io/knowledge-base/license-installation-type/")}
                                rel="noreferrer"
                                target="_blank"
                            >
                                {__("Learn more")}
                            </a>
                            )
                        </>
                    }
                    type="warning"
                    style={{ marginBottom: "10px" }}
                />
            )}
            {/** Show Tax switch if more than one taxonomy is available */}
            {!isPro && showProHints && showLiteNotice && <ProFooter closeable />}
            {Object.keys(taxos).length > 1 && (
                <div style={{ margin: "2px 0px 9px 0", textAlign: "right" }}>
                    <TaxSwitcher disabled={!!toolbarActiveButton} />
                </div>
            )}
        </Tree>
    );
});

export { AppTree };
