import { __esDecorate, __runInitializers } from "tslib";
import { html, nothing } from 'lit';
import { state } from 'lit/decorators.js';
import { ApiModelingScreen } from './ApiModelingScreen.js';
let ApiModelingActionsScreen = (() => {
    let _classSuper = ApiModelingScreen;
    let _hasDomain_decorators;
    let _hasDomain_initializers = [];
    let _hasDomain_extraInitializers = [];
    let _exposed_decorators;
    let _exposed_initializers = [];
    let _exposed_extraInitializers = [];
    return class ApiModelingActionsScreen extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _hasDomain_decorators = [state()];
            _exposed_decorators = [state()];
            __esDecorate(this, null, _hasDomain_decorators, { kind: "accessor", name: "hasDomain", static: false, private: false, access: { has: obj => "hasDomain" in obj, get: obj => obj.hasDomain, set: (obj, value) => { obj.hasDomain = value; } }, metadata: _metadata }, _hasDomain_initializers, _hasDomain_extraInitializers);
            __esDecorate(this, null, _exposed_decorators, { kind: "accessor", name: "exposed", static: false, private: false, access: { has: obj => "exposed" in obj, get: obj => obj.exposed, set: (obj, value) => { obj.exposed = value; } }, metadata: _metadata }, _exposed_initializers, _exposed_extraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        #hasDomain_accessor_storage = __runInitializers(this, _hasDomain_initializers, false
        /**
         * The list of exposed entities **on the root level**.
         */
        );
        /**
         * A flag that determines whether the API has added a data domain.
         */
        get hasDomain() { return this.#hasDomain_accessor_storage; }
        set hasDomain(value) { this.#hasDomain_accessor_storage = value; }
        #exposed_accessor_storage = (__runInitializers(this, _hasDomain_extraInitializers), __runInitializers(this, _exposed_initializers, []));
        /**
         * The list of exposed entities **on the root level**.
         */
        get exposed() { return this.#exposed_accessor_storage; }
        set exposed(value) { this.#exposed_accessor_storage = value; }
        handleModelChange(model) {
            this.hasDomain = false;
            this.exposed = [];
            if (!model) {
                return;
            }
            if (!model.domain) {
                return;
            }
            this.hasDomain = true;
            this.exposed = model.exposes.filter((expose) => expose.isRoot);
        }
        handleDomainChange() {
            // TODO: this is too much for a model change, but temporary we will re-render the screen on any model change
            // until we figure out how to expose a new entity to the API and capture only that change.
            this.handleModelChange(this.model);
            this.requestUpdate();
        }
        /**
         * A handler for the "Add data" button click.
         * It dispatches the `exposeentity` event to notify the parent component that the user wants to expose an entity.
         */
        handleAddDataClick() {
            this.dispatchEvent(new Event('exposed-new'));
        }
        /**
         * A handler for the "Remove action" button click.
         * It removes the action from the model and updates the exposed list.
         * @param event The event object.
         */
        handleRemoveAction(e) {
            const card = e.currentTarget;
            const id = card.domainKey;
            if (!id) {
                return;
            }
            this.dispatchEvent(new CustomEvent('exposed-remove', {
                detail: {
                    exposedId: id,
                },
            }));
        }
        /**
         * Handles the action selection event.
         * It dispatches the `editaction` event to notify the parent component that the user wants to edit an action.
         * @param e The event object.
         */
        handleActionSelect(e) {
            const card = e.currentTarget;
            const id = card.domainKey;
            if (!id) {
                return;
            }
            this.dispatchEvent(new CustomEvent('action-edit', {
                detail: {
                    exposedId: id,
                    kind: e.detail.kind,
                },
            }));
        }
        handleEditAction(e) {
            const card = e.currentTarget;
            const id = card.domainKey;
            if (!id) {
                return;
            }
            this.dispatchEvent(new CustomEvent('exposed-edit', {
                detail: {
                    exposedId: id,
                },
            }));
        }
        render() {
            const model = this.model;
            if (!model) {
                return nothing;
            }
            return html `
      <div class="config-section horizontal center">
        <div class="section-header">
          <h2 class="headline-medium">API Actions</h2>
          <p class="body-medium">
            You define your API logic by selecting data objects you want to use in your API and adding predefined
            actions to these data.
          </p>
        </div>
        <ui-button @click="${this.handleAddDataClick}">Add data</ui-button>
      </div>
      ${this.hasDomain ? this.renderContent(model) : html `<p>No data domain selected.</p>`}
    `;
        }
        renderContent(model) {
            if (!this.exposed.length) {
                return this.renderEmptyView();
            }
            return html `<div class="exposed-canvas">
      ${this.exposed.map((expose) => this.renderExposedPath(model, expose))}
    </div>`;
        }
        renderEmptyView() {
            return html `
      <section class="empty-screen">
        <div class="icon-wrapper">
          <ui-icon class="icon" icon="api"></ui-icon>
        </div>
        <p class="empty-message body-large">Find your API logic here</p>
        <p class="empty-message body-medium">Add a data entity to define your API behavior.</p>
      </section>
    `;
        }
        renderExposedPath(model, rootExpose) {
            // Render the root expose and all its nested children (by parent key) in a single row.
            // Use the model.exposes list as the source of truth for child relationships.
            const allExposes = model.exposes ?? [];
            const row = this.renderExposeTree(model, rootExpose, allExposes);
            return html `<div class="exposure-row">${row}</div>`;
        }
        /**
         * Recursively render an expose and its children. Shows entity name only.
         * The model guarantees no infinite cycles, so the UI does not need to track visited nodes.
         */
        renderExposeTree(model, rootExpose, allExposes) {
            if (!rootExpose || !rootExpose.key) {
                return nothing;
            }
            // Render current entity
            const current = this.renderEntity(model, rootExpose);
            // Find children that reference this expose as parent.
            const children = allExposes.filter((e) => e.parent?.key === rootExpose.key);
            // If no children, render just the entity
            if (!children.length) {
                return html `<div class="expose-node inline">${current}</div>`;
            }
            // Render current entity and stack children vertically. Each child row shows
            // the child and its inline descendants (classic tree view).
            return html `${current}
      <div class="children-list">
        ${children.map((child) => html `
            <div class="child-row">
              <span class="expose-sep">→</span>
              ${this.renderExposeTree(model, child, allExposes)}
            </div>
          `)}
      </div>`;
            // <!-- ${this.renderExposeInline(model, child, allExposes)} -->
        }
        /**
         * Render a node and all its descendants inline (used for child rows).
         */
        renderExposeInline(model, expose, allExposes) {
            if (!expose || !expose.key) {
                return nothing;
            }
            const current = this.renderEntity(model, expose);
            const children = allExposes.filter((e) => {
                const parentRef = e.parent;
                const parentKey = parentRef?.key;
                return parentKey === expose.key;
            });
            if (!children.length) {
                return html `${current}`;
            }
            return html `${current}${children.map((child) => html `
        <span class="expose-sep">→</span>
        ${this.renderExposeInline(model, child, allExposes)}
      `)}`;
        }
        renderEntity(model, expose) {
            const entity = model.domain?.findEntity(expose.entity.key, expose.entity.domain);
            if (!entity) {
                return this.renderMissingEntity(expose);
            }
            return html `<api-modeling-entity-card
      .model=${model}
      .domainKey=${expose.key}
      ?showCollectionActions="${expose.hasCollection}"
      @select="${this.handleActionSelect}"
      @edit="${this.handleEditAction}"
      @remove="${this.handleRemoveAction}"
    ></api-modeling-entity-card>`;
        }
        renderMissingEntity(expose) {
            return html `<div class="entity missing-entity">
      <span class="entity-missing-label">Missing entity:</span>
      <span class="api-action-entity">${expose.key}</span>
    </div>`;
        }
        renderEntityActions(expose) {
            const hasActions = !!expose.actions.length;
            if (!hasActions) {
                return html `<div class="no-actions">
        <p class="body-medium">No API actions are defined for this object.</p>
      </div>`;
            }
            return html `${this.renderCollectionActions(expose)}${this.renderResourceActions(expose)}`;
        }
        renderCollectionActions(expose) {
            const actions = expose.actions.filter((action) => ['create', 'list', 'search'].includes(action.kind));
            const hasActions = !!actions.length;
            const templates = [];
            if (!hasActions) {
                templates.push(html `<p class="body-medium">No API actions are defined for this collection.</p>`);
            }
            else {
                templates.push(...actions.map((action) => this.renderEntityAction(action)));
            }
            return html `<div class="actions-group">
      <div class="label-small">Collection</div>
      ${templates}
    </div>`;
        }
        renderResourceActions(expose) {
            const actions = expose.actions.filter((action) => ['read', 'update', 'delete'].includes(action.kind));
            const hasActions = !!actions.length;
            const templates = [];
            if (!hasActions) {
                templates.push(html `<p class="body-medium">No API actions are defined for this resource.</p>`);
            }
            else {
                templates.push(...actions.map((action) => this.renderEntityAction(action)));
            }
            return html `<div class="actions-group">
      <div class="label-small">Resource</div>
      ${templates}
    </div>`;
        }
        renderEntityAction(action) {
            return html `<ui-chip type="assist">${action.kind}</ui-chip>`;
        }
        constructor() {
            super(...arguments);
            __runInitializers(this, _exposed_extraInitializers);
        }
    };
})();
/**
 * A screen that allows the user to expose data entities as a root level actions
 * and configure their properties:
 * - Collection actions (create, list, search)
 * - Resource actions (read, update, delete)
 *
 * @fires exposed-new - When the user wants to expose an entity.
 * @fires action-edit - When the user wants to edit an action.
 * @fires exposed-edit - When the user wants to edit an exposed entity.
 * @fires exposed-remove - When the user wants to remove an exposed entity.
 */
export default ApiModelingActionsScreen;
//# sourceMappingURL=ApiModelingActionsScreen.js.map