import { UMB_MENU_VARIANT_STRUCTURE_WORKSPACE_CONTEXT } from './menu-variant-structure-workspace-context.context-token.js';
import { UMB_SECTION_SIDEBAR_MENU_SECTION_CONTEXT } from './section-sidebar-menu/section-context/section-sidebar-menu.section-context.token.js';
import { createExtensionApiByAlias } from '../extension-registry/index.js';
import { UmbContextBase } from '../../../libs/class-api/index.js';
import { UmbArrayState, UmbObjectState } from '../../../libs/observable-api/index.js';
import { UmbAncestorsEntityContext, UmbParentEntityContext } from '../entity/index.js';
import { UMB_SUBMITTABLE_TREE_ENTITY_WORKSPACE_CONTEXT, UMB_VARIANT_WORKSPACE_CONTEXT, UMB_WORKSPACE_EDIT_PATH_PATTERN, UMB_WORKSPACE_EDIT_VARIANT_PATH_PATTERN, } from '../workspace/index.js';
import { linkEntityExpansionEntries } from '../utils/index.js';
import { UMB_MODAL_CONTEXT } from '../modal/index.js';
import { UMB_SECTION_CONTEXT } from '../section/index.js';
import { UmbVariantId } from '../variant/index.js';
// TODO: introduce base class for all menu structure workspaces to handle ancestors and parent
export class UmbMenuVariantTreeStructureWorkspaceContextBase extends UmbContextBase {
    #workspaceContext;
    #args;
    #structure;
    #parent;
    #parentContext;
    #ancestorContext;
    #sectionSidebarMenuContext;
    #isModalContext;
    #isNew;
    #variantWorkspaceContext;
    #workspaceActiveVariantId;
    constructor(host, args) {
        super(host, UMB_MENU_VARIANT_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;
        this.IS_MENU_VARIANT_STRUCTURE_WORKSPACE_CONTEXT = true;
        // '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_CONTEXT, (instance) => {
            this._sectionContext = instance;
        });
        this.consumeContext(UMB_VARIANT_WORKSPACE_CONTEXT, (instance) => {
            if (!instance)
                return;
            this.#variantWorkspaceContext = instance;
            this.#observeWorkspaceActiveVariant();
        });
        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');
        });
    }
    getItemHref(structureItem) {
        const sectionName = this._sectionContext?.getPathname();
        if (!sectionName)
            return undefined;
        const unique = structureItem.unique;
        if (!unique)
            return undefined;
        // find related variant id from structure item:
        const itemVariantFit = structureItem.variants.find((variant) => variant.culture === this.#workspaceActiveVariantId?.culture &&
            variant.segment === this.#workspaceActiveVariantId?.segment);
        if (itemVariantFit) {
            const variantId = UmbVariantId.CreateFromPartial(itemVariantFit);
            return UMB_WORKSPACE_EDIT_VARIANT_PATH_PATTERN.generateAbsolute({
                sectionName,
                entityType: structureItem.entityType,
                unique,
                variantId: variantId.toString(),
            });
        }
        // If no related variantID, then lets the redirect go to the main-variant:
        return UMB_WORKSPACE_EDIT_PATH_PATTERN.generateAbsolute({
            sectionName,
            entityType: structureItem.entityType,
            unique,
        });
    }
    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');
        // TODO: introduce variant tree item model
        const treeRepository = await createExtensionApiByAlias(this, this.#args.treeRepositoryAlias);
        const { data: root } = await treeRepository.requestTreeRoot();
        if (root) {
            structureItems = [
                {
                    unique: root.unique,
                    entityType: root.entityType,
                    variants: [{ name: root.name, culture: null, segment: null }],
                },
            ];
        }
        const { data } = await treeRepository.requestTreeItemAncestors({ treeItem: { unique, entityType } });
        if (data) {
            const treeItemAncestors = data.map((treeItem) => {
                return {
                    unique: treeItem.unique,
                    entityType: treeItem.entityType,
                    variants: treeItem.variants.map((variant) => {
                        return {
                            name: variant.name,
                            culture: variant.culture,
                            segment: variant.segment,
                        };
                    }),
                };
            });
            structureItems.push(...treeItemAncestors);
            this.#structure.setValue(structureItems);
            this.#setParentData(structureItems);
            this.#setAncestorData(data);
            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);
    }
    #observeWorkspaceActiveVariant() {
        this.observe(this.#variantWorkspaceContext?.splitView.activeVariantsInfo, (value) => {
            if (!value)
                return;
            if (value?.length === 0)
                return;
            this.#workspaceActiveVariantId = UmbVariantId.Create(value[0]);
        }, 'breadcrumbWorkspaceActiveVariantObserver');
    }
    destroy() {
        super.destroy();
        this.#structure.destroy();
        this.#parent.destroy();
        this.#parentContext.destroy();
        this.#ancestorContext.destroy();
    }
}
