import { UMB_MENU_STRUCTURE_WORKSPACE_CONTEXT } from './menu-structure-workspace-context.context-token.js';
import { UMB_SECTION_SIDEBAR_MENU_SECTION_CONTEXT } from './section-sidebar-menu/index.js';
import { createExtensionApiByAlias } from '../extension-registry/index.js';
import { UmbContextBase } from '../../../libs/class-api/index.js';
import { UMB_SUBMITTABLE_TREE_ENTITY_WORKSPACE_CONTEXT } from '../workspace/index.js';
import { UmbArrayState, UmbObjectState } from '../../../libs/observable-api/index.js';
import { UmbAncestorsEntityContext, UmbParentEntityContext } from '../entity/index.js';
import { linkEntityExpansionEntries } from '../utils/index.js';
import { UMB_MODAL_CONTEXT } from '../modal/index.js';
// TODO: introduce base class for all menu structure workspaces to handle ancestors and parent
export class UmbMenuTreeStructureWorkspaceContextBase extends UmbContextBase {
    #workspaceContext;
    #args;
    #structure;
    #parent;
    #parentContext;
    #ancestorContext;
    #sectionSidebarMenuContext;
    #isModalContext;
    #isNew;
    constructor(host, args) {
        super(host, UMB_MENU_STRUCTURE_WORKSPACE_CONTEXT);
        this.#structure = new UmbArrayState([], (x) => x.unique);
        this.structure = this.#structure.asObservable();
        this.#parent = new UmbObjectState(undefined);
        /**
         * @deprecated Will be removed in v.18: Use UMB_PARENT_ENTITY_CONTEXT instead.
         */
        this.parent = this.#parent.asObservable();
        this.#parentContext = new UmbParentEntityContext(this);
        this.#ancestorContext = new UmbAncestorsEntityContext(this);
        this.#isModalContext = false;
        this.#isNew = undefined;
        // 'UmbMenuStructureWorkspaceContext' is Obsolete, will be removed in v.18
        this.provideContext('UmbMenuStructureWorkspaceContext', this);
        this.#args = args;
        this.consumeContext(UMB_MODAL_CONTEXT, (modalContext) => {
            this.#isModalContext = modalContext !== undefined;
        });
        this.consumeContext(UMB_SECTION_SIDEBAR_MENU_SECTION_CONTEXT, (instance) => {
            this.#sectionSidebarMenuContext = instance;
        });
        this.consumeContext(UMB_SUBMITTABLE_TREE_ENTITY_WORKSPACE_CONTEXT, (instance) => {
            this.#workspaceContext = instance;
            this.observe(this.#workspaceContext?.unique, (value) => {
                if (!value)
                    return;
                this.#requestStructure();
            }, 'observeUnique');
            this.observe(this.#workspaceContext?.isNew, (value) => {
                // Workspace has changed from new to existing
                if (value === false && this.#isNew === true) {
                    // TODO: We do not need to request here as we already know the structure and unique
                    this.#requestStructure();
                }
                this.#isNew = value;
            }, 'observeIsNew');
        });
    }
    async #requestStructure() {
        const isNew = this.#workspaceContext?.getIsNew();
        const uniqueObservable = isNew
            ? this.#workspaceContext?._internal_createUnderParentEntityUnique
            : this.#workspaceContext?.unique;
        const entityTypeObservable = isNew
            ? this.#workspaceContext?._internal_createUnderParentEntityType
            : this.#workspaceContext?.entityType;
        let structureItems = [];
        const unique = (await this.observe(uniqueObservable, () => { })?.asPromise());
        if (unique === undefined)
            throw new Error('Unique is not available');
        const entityType = (await this.observe(entityTypeObservable, () => { })?.asPromise());
        if (!entityType)
            throw new Error('Entity type is not available');
        const treeRepository = await createExtensionApiByAlias(this, this.#args.treeRepositoryAlias);
        const { data: root } = await treeRepository.requestTreeRoot();
        if (root) {
            structureItems = [
                {
                    unique: root.unique,
                    entityType: root.entityType,
                    name: root.name,
                    isFolder: root.isFolder,
                },
            ];
        }
        const isRoot = entityType === root?.entityType;
        // If the entity type is different from the root entity type, then we can request the ancestors.
        if (!isRoot) {
            const { data } = await treeRepository.requestTreeItemAncestors({ treeItem: { unique, entityType } });
            if (data) {
                const ancestorItems = data.map((treeItem) => {
                    return {
                        unique: treeItem.unique,
                        entityType: treeItem.entityType,
                        name: treeItem.name,
                        isFolder: treeItem.isFolder,
                    };
                });
                this.#setAncestorData(data);
                structureItems.push(...ancestorItems);
            }
        }
        this.#structure.setValue(structureItems);
        this.#setParentData(structureItems);
        const menuItemAlias = this.manifest?.meta?.menuItemAlias;
        if (menuItemAlias && !this.#isModalContext) {
            this.#expandSectionSidebarMenu(structureItems, menuItemAlias);
        }
    }
    #setParentData(structureItems) {
        /* If the item is not new, the current item is the last item in the array.
            We filter out the current item unique to handle any case where it could show up */
        const parent = structureItems.filter((item) => item.unique !== this.#workspaceContext?.getUnique()).pop();
        // TODO: remove this when the parent gets removed from the structure interface
        this.#parent.setValue(parent);
        const parentEntity = parent
            ? {
                unique: parent.unique,
                entityType: parent.entityType,
            }
            : undefined;
        this.#parentContext.setParent(parentEntity);
    }
    /* Notice: ancestors are based on the server "data" ancestors and are not based on the full Menu (UI) structure.
        This will mean that any item placed in the data root will not have any ancestors. But will have a parent based on the UI structure.
    */
    #setAncestorData(ancestors) {
        const ancestorEntities = ancestors
            .map((treeItem) => {
            const entity = {
                unique: treeItem.unique,
                entityType: treeItem.entityType,
            };
            return entity;
        })
            /* If the item is not new, the current item is the last item in the array.
                We filter out the current item unique to handle any case where it could show up */
            .filter((item) => item.unique !== this.#workspaceContext?.getUnique());
        this.#ancestorContext.setAncestors(ancestorEntities);
    }
    #expandSectionSidebarMenu(structureItems, menuItemAlias) {
        const linkedEntries = linkEntityExpansionEntries(structureItems);
        // Filter out the current entity as we don't want to expand it
        const expandableItems = linkedEntries.filter((item) => item.unique !== this.#workspaceContext?.getUnique());
        const expandableItemsWithMenuItem = expandableItems.map((item) => {
            return {
                ...item,
                menuItemAlias,
            };
        });
        this.#sectionSidebarMenuContext?.expansion.expandItems(expandableItemsWithMenuItem);
    }
    destroy() {
        super.destroy();
        this.#structure.destroy();
        this.#parent.destroy();
        this.#parentContext.destroy();
        this.#ancestorContext.destroy();
    }
}
