var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { umbExtensionsRegistry } from '../../registry.js';
import { css, repeat, customElement, property, state, html, nothing } from '../../../../../external/lit/index.js';
import { UmbExtensionsElementAndApiInitializer, } from '../../../../../libs/extension-api/index.js';
import { UmbLitElement } from '../../../lit-element/index.js';
/**
 * A custom element that dynamically renders extensions with both UI elements and API classes.
 *
 * Similar to `umb-extension-slot`, this element observes the extension registry and renders permitted extensions.
 * The key difference is that this slot also initializes an API class for each extension, allowing extensions
 * to have both a visual component and associated business logic. The API instance is created with configurable
 * constructor arguments and can receive properties.
 * @element umb-extension-with-api-slot
 * @slot default - Fallback content shown when no extensions are permitted (unless `fallbackRenderMethod` is provided).
 * @example Basic usage - Render extensions with APIs
 * ```html
 * <umb-extension-with-api-slot type="entityAction"></umb-extension-with-api-slot>
 * ```
 * @example Multiple types - Render extensions from multiple types
 * ```html
 * <umb-extension-with-api-slot .type=${['workspaceAction', 'workspaceActionMenuItem']}></umb-extension-with-api-slot>
 * ```
 * @example Single extension - Only render the first matching extension
 * ```html
 * <umb-extension-with-api-slot type="collectionTextFilter" single></umb-extension-with-api-slot>
 * ```
 * @example With filter - Filter extensions by manifest properties
 * ```html
 * <umb-extension-with-api-slot
 *     type="entityAction"
 *     .filter=${(manifest) => manifest.forEntityTypes.includes(entityType)}>
 * </umb-extension-with-api-slot>
 * ```
 * @example With element props - Pass data to extension elements
 * ```html
 * <umb-extension-with-api-slot
 *     type="entityAction"
 *     .elementProps=${{ entityType, unique }}>
 * </umb-extension-with-api-slot>
 * ```
 * @example With API args - Pass constructor arguments to extension APIs
 * ```html
 * <umb-extension-with-api-slot
 *     type="workspaceAction"
 *     .apiArgs=${[workspaceContext]}>
 * </umb-extension-with-api-slot>
 * ```
 * @example With API args method - Dynamic constructor arguments based on manifest
 * ```html
 * <umb-extension-with-api-slot
 *     type="workspaceAction"
 *     .apiArgs=${(manifest) => [workspaceContext, manifest.meta]}>
 * </umb-extension-with-api-slot>
 * ```
 * @example Combined usage - Filter, element props, and API args
 * ```html
 * <umb-extension-with-api-slot
 *     type="entityAction"
 *     .filter=${this._filter}
 *     .elementProps=${this._props}
 *     .apiArgs=${this._apiArgs}
 *     .renderMethod=${(ext, index) => ext.component}>
 * </umb-extension-with-api-slot>
 * ```
 * @example Custom render method - Control how extensions are rendered
 * ```html
 * <umb-extension-with-api-slot
 *     type="menuItem"
 *     .renderMethod=${(ext, index) => html`
 *         <div class="menu-item-wrapper">
 *             ${ext.component}
 *         </div>
 *     `}>
 * </umb-extension-with-api-slot>
 * ```
 * @example Fallback content - Shows the slotted content when no extensions match
 * ```html
 * <umb-extension-with-api-slot type="myExtensionType">
 *     <p>No actions available</p>
 * </umb-extension-with-api-slot>
 * ```
 * @example Fallback render method - Shows the result of the fallbackRenderMethod when no extensions match
 * ```html
 * <umb-extension-with-api-slot type="myExtensionType">
 *     .fallbackRenderMethod=${() => html`<p>No extensions available</p>`}
 * </umb-extension-with-api-slot>
 * ```
 */
// TODO: Refactor extension-slot and extension-with-api slot.
// TODO: Fire change event.
// TODO: Make property that reveals the amount of displayed/permitted extensions.
let UmbExtensionWithApiSlotElement = class UmbExtensionWithApiSlotElement extends UmbLitElement {
    #attached = false;
    #extensionsController;
    #disconnectAC;
    /**
     * The type or types of extensions to render. Required for the slot to display anything.
     * Can be a single type string or an array of type strings to render extensions from multiple types.
     * @example Single type
     * ```html
     * <umb-extension-with-api-slot type="entityAction"></umb-extension-with-api-slot>
     * ```
     * @example Multiple types
     * ```html
     * <umb-extension-with-api-slot .type=${['workspaceAction', 'workspaceActionMenuItem']}></umb-extension-with-api-slot>
     * ```
     */
    get type() {
        return this.#type;
    }
    set type(value) {
        if (value === this.#type)
            return;
        this.#type = value;
        this.#observeExtensions();
    }
    #type;
    /**
     * Filter function for extension manifests.
     * This is an initial filter taking effect before conditions or overwrites are applied.
     * Extensions will still be filtered by their manifest-defined conditions after this filter.
     * The filter function receives the extension manifest and should return true to include it.
     * @example Filter by entity type
     * ```html
     * <umb-extension-with-api-slot
     *     type="entityAction"
     *     .filter=${(manifest) => manifest.forEntityTypes.includes(entityType)}>
     * </umb-extension-with-api-slot>
     * ```
     * @example Filter by meta properties
     * ```html
     * <umb-extension-with-api-slot
     *     type="workspaceAction"
     *     .filter=${(manifest) => manifest.meta.look === 'primary'}>
     * </umb-extension-with-api-slot>
     * ```
     */
    get filter() {
        return this.#filter;
    }
    set filter(value) {
        if (value === this.#filter)
            return;
        this.#filter = value;
        this.#observeExtensions();
    }
    #filter = () => true;
    /**
     * Properties to pass to all rendered extension elements.
     * These properties are spread onto each extension element instance.
     * Note: The extension's manifest is always passed automatically regardless of this setting.
     * @example Pass entity context to extension elements
     * ```html
     * <umb-extension-with-api-slot
     *     type="entityAction"
     *     .elementProps=${{ entityType: 'document', unique: documentId }}>
     * </umb-extension-with-api-slot>
     * ```
     */
    get elementProps() {
        return this.#elProps;
    }
    set elementProps(newVal) {
        // TODO, compare changes since last time. only reset the ones that changed. This might be better done by the controller is self:
        this.#elProps = newVal;
        if (this.#extensionsController) {
            this.#extensionsController.elementProperties = newVal;
        }
    }
    #elProps = {};
    /**
     * Constructor arguments to pass when instantiating the extension APIs.
     * Can be an array of arguments or a function that receives the manifest and returns arguments.
     * Note: The host controller is always prepended as the first argument automatically.
     * @example Static array of arguments
     * ```html
     * <umb-extension-with-api-slot
     *     type="workspaceAction"
     *     .apiArgs=${[workspaceContext]}>
     * </umb-extension-with-api-slot>
     * ```
     * @example Dynamic arguments based on manifest
     * ```html
     * <umb-extension-with-api-slot
     *     type="entityAction"
     *     .apiArgs=${(manifest) => [entityContext, manifest.meta.actionType]}>
     * </umb-extension-with-api-slot>
     * ```
     */
    get apiArgs() {
        return this.#constructorArgs;
    }
    set apiArgs(newVal) {
        if (newVal === this.#constructorArgs)
            return;
        this.#constructorArgs = newVal;
        this.#observeExtensions();
    }
    #constructorArgs = [];
    /**
     * Properties to pass to all extension API instances after construction.
     * These properties are spread onto each API instance.
     * Note: The extension's manifest is always passed automatically regardless of this setting.
     * @example Pass configuration to extension APIs
     * ```html
     * <umb-extension-with-api-slot
     *     type="workspaceAction"
     *     .apiProps=${{ saveOnClick: true, validateFirst: false }}>
     * </umb-extension-with-api-slot>
     * ```
     */
    get apiProps() {
        return this.#apiProps;
    }
    set apiProps(newVal) {
        // TODO, compare changes since last time. only reset the ones that changed. This might be better done by the controller is self:
        this.#apiProps = newVal;
        if (this.#extensionsController) {
            this.#extensionsController.apiProperties = newVal;
        }
    }
    #apiProps = {};
    connectedCallback() {
        super.connectedCallback();
        this.#attached = true;
        // Cancel any pending destruction if we're being reconnected (e.g., during a DOM move/sort)
        if (this.#disconnectAC) {
            this.#disconnectAC.abort();
            this.#disconnectAC = undefined;
            // Only skip re-initialization if the controller still exists
            if (this.#extensionsController) {
                return;
            }
        }
        this.#observeExtensions();
    }
    disconnectedCallback() {
        super.disconnectedCallback();
        this.#attached = false;
        // Abort any previously pending disconnect before scheduling a new one
        this.#disconnectAC?.abort();
        // Defer destruction to allow for reconnection during DOM moves/sorting
        // If reconnected before the microtask resolves, the AbortController cancels the callback
        const abortController = (this.#disconnectAC = new AbortController());
        queueMicrotask(() => {
            if (!abortController.signal.aborted) {
                this.#disconnectAC = undefined;
                this.#extensionsController?.destroy();
                this.#extensionsController = undefined;
            }
        });
    }
    #observeExtensions() {
        // We want to be attached before we start observing extensions, cause first at this point we know that we got the right properties. [NL]
        if (!this.#attached)
            return;
        this.#extensionsController?.destroy();
        if (this.#type) {
            this.#extensionsController = new UmbExtensionsElementAndApiInitializer(this, umbExtensionsRegistry, this.#type, this.#constructorArgs, this.filter, (extensionControllers) => {
                this._permitted = extensionControllers;
            }, undefined, // We can leave the alias to undefined, as we destroy this our selfs.
            this.defaultElement, this.defaultApi, {
                single: this.single,
            });
            this.#extensionsController.apiProperties = this.#apiProps;
            this.#extensionsController.elementProperties = this.#elProps;
        }
    }
    render() {
        return this._permitted
            ? this._permitted.length > 0
                ? repeat(this._permitted, (ext) => ext.alias, this.#renderExtension)
                : this.#renderNoting()
            : nothing;
    }
    #renderNoting() {
        return this.fallbackRenderMethod ? this.fallbackRenderMethod() : html `<slot></slot>`;
    }
    #renderExtension = (ext, i) => {
        return this.renderMethod ? this.renderMethod(ext, i) : ext.component;
    };
    static { this.styles = css `
		:host {
			display: contents;
		}
	`; }
};
__decorate([
    state()
], UmbExtensionWithApiSlotElement.prototype, "_permitted", void 0);
__decorate([
    property({ type: Boolean })
], UmbExtensionWithApiSlotElement.prototype, "single", void 0);
__decorate([
    property({ type: String })
], UmbExtensionWithApiSlotElement.prototype, "type", null);
__decorate([
    property({ type: Object, attribute: false })
], UmbExtensionWithApiSlotElement.prototype, "filter", null);
__decorate([
    property({ attribute: false })
], UmbExtensionWithApiSlotElement.prototype, "elementProps", null);
__decorate([
    property({ attribute: false })
], UmbExtensionWithApiSlotElement.prototype, "apiArgs", null);
__decorate([
    property({ attribute: false })
], UmbExtensionWithApiSlotElement.prototype, "apiProps", null);
__decorate([
    property({ type: String, attribute: 'default-element' })
], UmbExtensionWithApiSlotElement.prototype, "defaultElement", void 0);
__decorate([
    property({ type: String, attribute: 'default-api' })
], UmbExtensionWithApiSlotElement.prototype, "defaultApi", void 0);
__decorate([
    property()
], UmbExtensionWithApiSlotElement.prototype, "renderMethod", void 0);
__decorate([
    property({ attribute: false })
], UmbExtensionWithApiSlotElement.prototype, "fallbackRenderMethod", void 0);
UmbExtensionWithApiSlotElement = __decorate([
    customElement('umb-extension-with-api-slot')
], UmbExtensionWithApiSlotElement);
export { UmbExtensionWithApiSlotElement };
