import { __esDecorate, __runInitializers } from "tslib";
import { LitElement, html, nothing } from 'lit';
import { property, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
let ShareFile = (() => {
    let _classSuper = LitElement;
    let _userSuggestions_decorators;
    let _userSuggestions_initializers = [];
    let _userSuggestions_extraInitializers = [];
    let _grant_decorators;
    let _grant_initializers = [];
    let _grant_extraInitializers = [];
    let _permissionUsers_decorators;
    let _permissionUsers_initializers = [];
    let _permissionUsers_extraInitializers = [];
    let _permissions_decorators;
    let _permissions_initializers = [];
    let _permissions_extraInitializers = [];
    let _multiple_decorators;
    let _multiple_initializers = [];
    let _multiple_extraInitializers = [];
    let _pending_decorators;
    let _pending_initializers = [];
    let _pending_extraInitializers = [];
    let __addedUsers_decorators;
    let __addedUsers_initializers = [];
    let __addedUsers_extraInitializers = [];
    let _error_decorators;
    let _error_initializers = [];
    let _error_extraInitializers = [];
    return class ShareFile extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _userSuggestions_decorators = [property({ type: Array, attribute: false })];
            _grant_decorators = [property({ type: String })];
            _permissionUsers_decorators = [property({ type: Array, attribute: false })];
            _permissions_decorators = [property({ type: Array, attribute: false })];
            _multiple_decorators = [property({ type: Boolean })];
            _pending_decorators = [state()];
            __addedUsers_decorators = [state()];
            _error_decorators = [property()];
            __esDecorate(this, null, _userSuggestions_decorators, { kind: "accessor", name: "userSuggestions", static: false, private: false, access: { has: obj => "userSuggestions" in obj, get: obj => obj.userSuggestions, set: (obj, value) => { obj.userSuggestions = value; } }, metadata: _metadata }, _userSuggestions_initializers, _userSuggestions_extraInitializers);
            __esDecorate(this, null, _grant_decorators, { kind: "accessor", name: "grant", static: false, private: false, access: { has: obj => "grant" in obj, get: obj => obj.grant, set: (obj, value) => { obj.grant = value; } }, metadata: _metadata }, _grant_initializers, _grant_extraInitializers);
            __esDecorate(this, null, _permissionUsers_decorators, { kind: "accessor", name: "permissionUsers", static: false, private: false, access: { has: obj => "permissionUsers" in obj, get: obj => obj.permissionUsers, set: (obj, value) => { obj.permissionUsers = value; } }, metadata: _metadata }, _permissionUsers_initializers, _permissionUsers_extraInitializers);
            __esDecorate(this, null, _permissions_decorators, { kind: "accessor", name: "permissions", static: false, private: false, access: { has: obj => "permissions" in obj, get: obj => obj.permissions, set: (obj, value) => { obj.permissions = value; } }, metadata: _metadata }, _permissions_initializers, _permissions_extraInitializers);
            __esDecorate(this, null, _multiple_decorators, { kind: "accessor", name: "multiple", static: false, private: false, access: { has: obj => "multiple" in obj, get: obj => obj.multiple, set: (obj, value) => { obj.multiple = value; } }, metadata: _metadata }, _multiple_initializers, _multiple_extraInitializers);
            __esDecorate(this, null, _pending_decorators, { kind: "accessor", name: "pending", static: false, private: false, access: { has: obj => "pending" in obj, get: obj => obj.pending, set: (obj, value) => { obj.pending = value; } }, metadata: _metadata }, _pending_initializers, _pending_extraInitializers);
            __esDecorate(this, null, __addedUsers_decorators, { kind: "accessor", name: "_addedUsers", static: false, private: false, access: { has: obj => "_addedUsers" in obj, get: obj => obj._addedUsers, set: (obj, value) => { obj._addedUsers = value; } }, metadata: _metadata }, __addedUsers_initializers, __addedUsers_extraInitializers);
            __esDecorate(this, null, _error_decorators, { kind: "accessor", name: "error", static: false, private: false, access: { has: obj => "error" in obj, get: obj => obj.error, set: (obj, value) => { obj.error = value; } }, metadata: _metadata }, _error_initializers, _error_extraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        #userSuggestions_accessor_storage = __runInitializers(this, _userSuggestions_initializers, []
        /**
         * The current grant/permission role for new shares.
         *
         * @attribute
         */
        );
        /**
         * The users available for sharing.
         * This property should be set by the hosting application in response to `search-users` events.
         */
        get userSuggestions() { return this.#userSuggestions_accessor_storage; }
        set userSuggestions(value) { this.#userSuggestions_accessor_storage = value; }
        #grant_accessor_storage = (__runInitializers(this, _userSuggestions_extraInitializers), __runInitializers(this, _grant_initializers, 'writer'
        /**
         * The users that already have permissions.
         */
        ));
        /**
         * The current grant/permission role for new shares.
         *
         * @attribute
         */
        get grant() { return this.#grant_accessor_storage; }
        set grant(value) { this.#grant_accessor_storage = value; }
        #permissionUsers_accessor_storage = (__runInitializers(this, _grant_extraInitializers), __runInitializers(this, _permissionUsers_initializers, []
        /**
         * The existing permissions on the file(s).
         *
         * - When there's only one file, this will contain the existing permissions for that file.
         * - When multiple files are being shared, this will contain the common permissions
         *   that can be set for all files.
         */
        ));
        /**
         * The users that already have permissions.
         */
        get permissionUsers() { return this.#permissionUsers_accessor_storage; }
        set permissionUsers(value) { this.#permissionUsers_accessor_storage = value; }
        #permissions_accessor_storage = (__runInitializers(this, _permissionUsers_extraInitializers), __runInitializers(this, _permissions_initializers, []
        /**
         * A flag indicating whether multiple files are being shared.
         * @attribute
         */
        ));
        /**
         * The existing permissions on the file(s).
         *
         * - When there's only one file, this will contain the existing permissions for that file.
         * - When multiple files are being shared, this will contain the common permissions
         *   that can be set for all files.
         */
        get permissions() { return this.#permissions_accessor_storage; }
        set permissions(value) { this.#permissions_accessor_storage = value; }
        #multiple_accessor_storage = (__runInitializers(this, _permissions_extraInitializers), __runInitializers(this, _multiple_initializers, false
        /**
         * Pending operations that haven't been committed yet
         */
        ));
        /**
         * A flag indicating whether multiple files are being shared.
         * @attribute
         */
        get multiple() { return this.#multiple_accessor_storage; }
        set multiple(value) { this.#multiple_accessor_storage = value; }
        #pending_accessor_storage = (__runInitializers(this, _multiple_extraInitializers), __runInitializers(this, _pending_initializers, new Map()
        /**
         * A map to store user details for pending add operations.
         */
        ));
        /**
         * Pending operations that haven't been committed yet
         */
        get pending() { return this.#pending_accessor_storage; }
        set pending(value) { this.#pending_accessor_storage = value; }
        #_addedUsers_accessor_storage = (__runInitializers(this, _pending_extraInitializers), __runInitializers(this, __addedUsers_initializers, new Map()
        /**
         * An error message to display when the `currentState` is set to `Error`.
         * @attribute
         */
        ));
        /**
         * A map to store user details for pending add operations.
         */
        get _addedUsers() { return this.#_addedUsers_accessor_storage; }
        set _addedUsers(value) { this.#_addedUsers_accessor_storage = value; }
        #error_accessor_storage = (__runInitializers(this, __addedUsers_extraInitializers), __runInitializers(this, _error_initializers, void 0));
        /**
         * An error message to display when the `currentState` is set to `Error`.
         * @attribute
         */
        get error() { return this.#error_accessor_storage; }
        set error(value) { this.#error_accessor_storage = value; }
        /**
         * A handler for the input event on the user search field.
         * Dispatches the `search-users` event.
         *
         * @param event The input event
         */
        handleNameInput(event) {
            const input = event.target;
            const value = input.value.trim();
            if (!value) {
                return;
            }
            this.dispatchEvent(new CustomEvent('search-users', {
                detail: { query: value },
                bubbles: false,
                composed: false,
            }));
        }
        /**
         * A handler for the keydown event on the user search field.
         * It focuses on the last selected user when Backspace is pressed and the input is empty.
         *
         * @param event The keyboard event
         */
        handleNameInputKeydown(event) {
            if (event.key === 'Backspace') {
                const input = event.target;
                if (input.value.length === 0) {
                    // Check if we have any pending adds (newly selected users)
                    // Since pending is a Map, we can check size, but we need to ensure they are adds.
                    const hasAdds = Array.from(this.pending.values()).some((op) => op.op === 'add');
                    if (hasAdds) {
                        // If the input is empty and there are selected users, focus the last chip.
                        const lastChip = this.renderRoot.querySelector('.share-input .chip:last-of-type');
                        if (lastChip) {
                            lastChip.focus();
                        }
                    }
                }
            }
        }
        /**
         * A handler for keydown events on the user suggestions list.
         * Stops propagation of the Escape key to prevent closing parent dialogs unexpectedly.
         *
         * @param event The keyboard event
         */
        handleUserSuggestionsKeydown(event) {
            if (event.key === 'Escape') {
                event.stopPropagation();
            }
        }
        /**
         * A handler for the autocomplete event when a user suggestion is selected.
         * Adds the user to the pending operations and dispatches `pending-changed`.
         *
         * @param event The custom event from the autocomplete input containing the selected item
         */
        handleUserSuggestion(event) {
            const { key } = event.detail.item.dataset;
            if (!key) {
                return;
            }
            const index = this.userSuggestions.findIndex((u) => u.key === key);
            if (index === -1) {
                // User not found in suggestions, do nothing.
                return;
            }
            const user = this.userSuggestions[index];
            if (this.pending.has(user.key)) {
                // User already in pending, do nothing.
                return;
            }
            const op = {
                op: 'add',
                id: user.key,
                value: this.grant,
                type: 'user',
            };
            this.pending.set(user.key, op);
            this._addedUsers.set(user.key, user);
            this.dispatchEvent(new CustomEvent('pending-changed', {
                detail: { pending: this.pending },
                composed: true,
                bubbles: true,
            }));
            const input = this.renderRoot.querySelector('.native-input');
            if (input) {
                input.value = '';
            }
            // Remove from suggestions
            this.userSuggestions = this.userSuggestions.filter((u) => u.key !== key);
        }
        /**
         * A handler for the remove event on a user chip.
         * Removing a user chip puts the user back into the suggestions list.
         *
         * @param e The event triggered by the chip removal
         */
        handleChipClose(e) {
            const chip = e.target;
            const key = chip.dataset.key;
            if (!key) {
                return;
            }
            if (this.pending.has(key)) {
                this.pending.delete(key);
                const removedUser = this._addedUsers.get(key);
                this._addedUsers.delete(key);
                if (removedUser) {
                    this.userSuggestions = [...this.userSuggestions, removedUser];
                }
                this.dispatchEvent(new CustomEvent('pending-changed', {
                    detail: { pending: this.pending },
                    composed: true,
                    bubbles: true,
                }));
            }
            const input = this.renderRoot.querySelector('.native-input');
            if (input) {
                input.focus();
            }
        }
        /**
         * Focuses the input when the container is clicked to ensure a good UX.
         *
         * @param event The mouse event on the container
         */
        handleInputContainerClick(event) {
            const initialTarget = event.composedPath()[0];
            if (initialTarget.classList.contains('input-container')) {
                const input = this.renderRoot.querySelector('.native-input');
                if (input) {
                    input.focus();
                }
            }
        }
        /**
         * Handles the change event of the grant type selector for new shares.
         * Dispatches `grant-changed`.
         *
         * @param e The change event
         */
        handleGrantTypeChange(e) {
            const node = e.currentTarget;
            const { value } = node;
            if (!value) {
                return;
            }
            this.grant = value;
            // Update pending adds with new role
            let hasChanges = false;
            for (const [, op] of this.pending) {
                if (op.op === 'add') {
                    if (op.value !== this.grant) {
                        op.value = this.grant;
                        hasChanges = true;
                    }
                }
            }
            this.dispatchEvent(new CustomEvent('grant-changed', {
                detail: { grant: this.grant },
                composed: true,
                bubbles: true,
            }));
            if (hasChanges) {
                this.dispatchEvent(new CustomEvent('pending-changed', {
                    detail: { pending: this.pending },
                    composed: true,
                    bubbles: true,
                }));
                this.requestUpdate();
            }
        }
        /**
         * Handles changes to the permission role of an existing user.
         * Updates the pending operations and dispatches `pending-changed`.
         *
         * @param e The change event
         */
        handleUserRoleChange(e) {
            const node = e.currentTarget;
            const { value, name } = node;
            if (!value || !name.startsWith('permission-')) {
                return;
            }
            const key = name.replace('permission-', '');
            const permission = this.permissions.find((p) => p.granteeId === key);
            if (!permission) {
                return;
            }
            if (value === 'remove') {
                const patch = {
                    op: 'remove',
                    id: permission.key,
                    type: permission.type,
                };
                this.pending.set(permission.key, patch);
            }
            else {
                const newRole = value;
                if (newRole === permission.role) {
                    this.pending.delete(permission.key);
                }
                else {
                    const patch = {
                        op: 'update',
                        id: permission.key,
                        type: permission.type,
                        value: newRole,
                    };
                    this.pending.set(permission.key, patch);
                }
            }
            this.dispatchEvent(new CustomEvent('pending-changed', {
                detail: { pending: this.pending },
                composed: true,
                bubbles: true,
            }));
            this.requestUpdate();
        }
        render() {
            return html `${this.renderIntro()} ${this.renderInput()} ${this.renderPeopleWithAccess()}`;
        }
        /**
         * Renders the introductory text based on single or multiple file sharing.
         */
        renderIntro() {
            if (this.multiple) {
                return html `<p>Share the selected files with other users in your organization.</p>`;
            }
            return html `<p>Share the file with other users in your organization.</p>`;
        }
        /**
         * Renders the main input area including chips, text input and grant type selector.
         */
        renderInput() {
            const addedUsers = Array.from(this.pending.values())
                .filter((op) => op.op === 'add')
                .map((op) => this._addedUsers.get(op.id)) // op.id is key/granteeId for add ops
                .filter((u) => !!u);
            return html `<div class="share-input">
      <autocomplete-input
        class="autocomplete"
        @keydown="${this.handleUserSuggestionsKeydown}"
        @autocomplete="${this.handleUserSuggestion}"
      >
        <div slot="anchor" class="input-container" @click="${this.handleInputContainerClick}">
          ${addedUsers.map((user) => this.renderChip(user))}
          <input
            slot="input"
            class="native-input"
            type="text"
            name="input"
            autocomplete="off"
            placeholder="Enter name or email"
            @input="${this.handleNameInput}"
            @keydown="${this.handleNameInputKeydown}"
          />
        </div>
        ${this.renderUserSuggestions()}
      </autocomplete-input>
      ${this.renderGrantTypeSelector()}
    </div>`;
        }
        /**
         * Renders the list of user suggestions for autocomplete.
         */
        renderUserSuggestions() {
            if (this.userSuggestions.length === 0) {
                return nothing;
            }
            return html `<ui-listbox class="user-suggestions" slot="suggestions" aria-label="User suggestions">
      ${this.userSuggestions.map((user) => this.renderSuggestion(user))}
    </ui-listbox>`;
        }
        /**
         * Renders a single user suggestion item.
         * @param user The user object to render
         */
        renderSuggestion(user) {
            const email = user.email[0]?.email || '';
            return html `<ui-list-item
      lines="two"
      image="avatar"
      data-key="${user.key}"
      data-name="${user.name}"
      data-email="${email}"
      data-index="name email"
    >
      <div>${user.name}</div>
      <div slot="supporting-text">${email}</div>
      <ui-user-avatar slot="start" class="avatar body-medium" .user="${user}" type="icon"></ui-user-avatar>
    </ui-list-item>`;
        }
        /**
         * Renders a chip for a selected user.
         * @param user The user object to render
         */
        renderChip(user) {
            return html `<ui-chip class="chip" type="input" data-key="${user.key}" removable @remove="${this.handleChipClose}">
      <ui-user-avatar slot="avatar" class="avatar body-medium" .user="${user}" type="icon"></ui-user-avatar>
      ${user.name}
    </ui-chip>`;
        }
        /**
         * Renders the grant type selector (Writer/Reader) for new shares.
         */
        renderGrantTypeSelector() {
            const hasAdds = Array.from(this.pending.values()).some((op) => op.op === 'add');
            if (!hasAdds) {
                return nothing;
            }
            return html `
      <ui-select
        label="Access type"
        class="grant-type-input"
        name="grantType"
        .value="${this.grant}"
        @change="${this.handleGrantTypeChange}"
      >
        <ui-option value="writer">
          <div>Writer</div>
        </ui-option>
        <ui-option value="reader">
          <div>Reader</div>
        </ui-option>
      </ui-select>
    `;
        }
        /**
         * Renders the section showing people who already have access.
         */
        renderPeopleWithAccess() {
            const hasAdds = Array.from(this.pending.values()).some((op) => op.op === 'add');
            if (this.permissions.length === 0 || hasAdds) {
                return nothing;
            }
            return html `<div class="people-with-access section">
      <h3 class="title-medium">People with access</h3>
      <ui-list class="people-list" aria-label="People with access">
        ${this.permissions.map((permission) => this.renderPermission(permission))}
      </ui-list>
    </div>`;
        }
        /**
         * Renders a permission item/row for an existing user.
         * @param permission The permission object
         */
        renderPermission(permission) {
            const user = this.permissionUsers.find((u) => u.key === permission.granteeId);
            if (!user) {
                // User not found, this should generally not happen, unless the user was deleted
                // or deactivated.
                return html `<ui-list-item static class="deactivated"><div class="label">Deactivated user</div></ui-list-item>`;
            }
            const email = user.email[0]?.email || '';
            const pending = this.pending.get(permission.key);
            const classes = {
                'removed': pending?.op === 'remove',
                'permission-item': true,
            };
            return html `<ui-list-item lines="two" image="avatar" static class="${classMap(classes)}">
      <div class="permission-user-name">${user.name}</div>
      <div class="permission-user-email" slot="supporting-text">${email}</div>
      <ui-user-avatar slot="start" class="avatar body-medium" .user="${user}" type="icon"></ui-user-avatar>
      <div slot="end" class="permission-role">${this.renderSharedUserOptions(user, permission)}</div>
    </ui-list-item>`;
        }
        /**
         * Renders the role selector for an existing permission.
         * @param user The user associated with the permission
         * @param permission The permission object
         */
        renderSharedUserOptions(user, permission) {
            const { key } = user;
            if (permission.role === 'owner') {
                // Owners cannot change their own permissions.
                // The owner permission can only be changed by transferring ownership to another user.
                return html `<span class="immutable-permission">Owner</span>`;
            }
            const pending = this.pending.get(permission.key);
            let value = permission.role;
            if (pending) {
                if (pending.op === 'remove') {
                    value = 'remove';
                }
                else if (pending.op === 'update') {
                    value = pending.value;
                }
            }
            return html `<ui-select
      class="grant-type-input"
      name="permission-${key}"
      .value="${value}"
      @change="${this.handleUserRoleChange}"
      data-key="${key}"
    >
      <ui-option value="writer">
        <div>Writer</div>
      </ui-option>
      <ui-option value="reader">
        <div>Reader</div>
      </ui-option>
      <ui-divider></ui-divider>
      <ui-option value="remove">
        <div>Remove access</div>
      </ui-option>
    </ui-select>`;
        }
        constructor() {
            super(...arguments);
            __runInitializers(this, _error_extraInitializers);
        }
    };
})();
/**
 * An element that manages the internal state and logic for sharing a file.
 *
 * This component handles the different states of the file sharing process, including initialization,
 * readiness, error handling, and committing changes. However, the component does not implement any API calls.
 * The hosting application is responsible for performing the actual file sharing operations.
 *
 * The component is not 100% complete. Pending features include:
 * - Permissions on groups.
 * - Sharing with the organization.
 * - Moving ownership to another user.
 *
 * @fires search-users - Dispatched when the user types in the search input.
 *                     The detail object contains the `query` string.
 * @fires grant-changed - Dispatched when the grant type for new shares is changed.
 *                      The detail object contains the `grant` role.
 * @fires pending-changed - Dispatched when a permission change for an existing user is staged.
 *                        The detail object contains the `pending` map of operations.
 */
export default ShareFile;
//# sourceMappingURL=ShareFile.js.map