import { __esDecorate, __runInitializers } from "tslib";
import { html } from 'lit';
import { property, state } from 'lit/decorators.js';
import { live } from 'lit/directives/live.js';
import { UrlProcessor } from '@api-client/core/lib/parsers/UrlProcessor.js';
import { UrlEncoder } from '@api-client/core/lib/parsers/UrlEncoder.js';
import ApiElement from '../ApiElement.js';
import '../../md/button/ui-button.js';
import '../../md/icon-button/ui-icon-button.js';
import '../../md/dropdown-list/ui-dropdown-list.js';
import '../../md/list/ui-list.js';
import '../../md/list/ui-list-item.js';
import '../../md/switch/ui-switch.js';
import '../../md/divider/ui-divider.js';
import '../../md/icons/ui-icon.js';
import '../../md/text-field/ui-filled-text-field.js';
let UrlParamsForm = (() => {
    let _classSuper = ApiElement;
    let _instanceExtraInitializers = [];
    let _readOnly_decorators;
    let _readOnly_initializers = [];
    let _readOnly_extraInitializers = [];
    let _text_decorators;
    let _text_initializers = [];
    let _text_extraInitializers = [];
    let _set_value_decorators;
    let _textValue_decorators;
    let _textValue_initializers = [];
    let _textValue_extraInitializers = [];
    return class UrlParamsForm extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _readOnly_decorators = [property({ type: Boolean, reflect: true })];
            _text_decorators = [property({ type: Boolean, reflect: true })];
            _set_value_decorators = [property({ type: String })];
            _textValue_decorators = [state()];
            __esDecorate(this, null, _readOnly_decorators, { kind: "accessor", name: "readOnly", static: false, private: false, access: { has: obj => "readOnly" in obj, get: obj => obj.readOnly, set: (obj, value) => { obj.readOnly = value; } }, metadata: _metadata }, _readOnly_initializers, _readOnly_extraInitializers);
            __esDecorate(this, null, _text_decorators, { kind: "accessor", name: "text", static: false, private: false, access: { has: obj => "text" in obj, get: obj => obj.text, set: (obj, value) => { obj.text = value; } }, metadata: _metadata }, _text_initializers, _text_extraInitializers);
            __esDecorate(this, null, _set_value_decorators, { kind: "setter", name: "value", static: false, private: false, access: { has: obj => "value" in obj, set: (obj, value) => { obj.value = value; } }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _textValue_decorators, { kind: "accessor", name: "textValue", static: false, private: false, access: { has: obj => "textValue" in obj, get: obj => obj.textValue, set: (obj, value) => { obj.textValue = value; } }, metadata: _metadata }, _textValue_initializers, _textValue_extraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        parser = (__runInitializers(this, _instanceExtraInitializers), new UrlProcessor('/'));
        #readOnly_accessor_storage = __runInitializers(this, _readOnly_initializers, false
        /**
         * Whether the text editor is rendered instead of the form.
         * @attribute
         */
        );
        /**
         * When set the editor is in read only mode.
         * @attribute
         */
        get readOnly() { return this.#readOnly_accessor_storage; }
        set readOnly(value) { this.#readOnly_accessor_storage = value; }
        #text_accessor_storage = (__runInitializers(this, _readOnly_extraInitializers), __runInitializers(this, _text_initializers, false));
        /**
         * Whether the text editor is rendered instead of the form.
         * @attribute
         */
        get text() { return this.#text_accessor_storage; }
        set text(value) { this.#text_accessor_storage = value; }
        #value = (__runInitializers(this, _text_extraInitializers), '');
        /**
         * The current value of the editor.
         * @attribute
         */
        get value() {
            return this.#value;
        }
        set value(value) {
            const old = this.#value;
            if (old === value) {
                return;
            }
            this.#value = value;
            this.setupParser(value);
        }
        #textValue_accessor_storage = __runInitializers(this, _textValue_initializers, void 0);
        get textValue() { return this.#textValue_accessor_storage; }
        set textValue(value) { this.#textValue_accessor_storage = value; }
        update(cp) {
            if (cp.has('text')) {
                if (this.text) {
                    this.textValue = this.parser.search.toParamsString();
                }
                else {
                    this.textValue = undefined;
                }
            }
            super.update(cp);
        }
        setupParser(value) {
            if (value) {
                this.parser = new UrlProcessor(value);
            }
            else {
                this.parser = new UrlProcessor('/');
            }
            this.requestUpdate();
        }
        handleAdd() {
            this.addParameter();
        }
        addParameter() {
            if (this.readOnly) {
                return;
            }
            this.parser.search.append('', '');
            this.requestUpdate();
            this.focusLast();
        }
        async focusLast() {
            await this.updateComplete;
            const row = this.shadowRoot?.querySelector('.param-row:last-of-type');
            if (!row) {
                return;
            }
            try {
                const node = row.querySelector('.name-input input');
                if (node) {
                    node.focus();
                }
            }
            catch {
                // ...
            }
        }
        handleOption(e) {
            const element = e.detail.item;
            const { option } = element.dataset;
            if (!option) {
                return;
            }
            if (option === 'clear') {
                this.clear();
            }
            else if (option === 'text-editor') {
                this.toggle();
            }
        }
        /**
         * Toggles the state between form and text editors.
         */
        toggle() {
            this.text = !this.text;
        }
        /**
         * Removes all parameters.
         */
        clear() {
            this.parser.search.clear();
            this.updateValue();
            this.requestUpdate();
            if (this.text) {
                this.textValue = this.parser.search.toParamsString();
            }
        }
        /**
         * Updates name/value of a parameter on a specific index.
         */
        updateProperty(index, field, value) {
            const list = this.parser.search.list();
            list[index][field] = value;
            this.parser.search.update(index, list[index]);
            this.updateValue();
            if (this.text) {
                this.textValue = this.parser.search.toParamsString();
            }
        }
        /**
         * Removes a parameter from an index.
         */
        removeProperty(index) {
            this.parser.search.delete(index);
            this.updateValue();
            this.requestUpdate();
            if (this.text) {
                this.textValue = this.parser.search.toParamsString();
            }
        }
        /**
         * Toggles enabled state of a parameter.
         */
        toggleProperty(index, enabled) {
            this.parser.search.toggle(index, enabled);
            this.updateValue();
            if (this.text) {
                this.textValue = this.parser.search.toParamsString();
            }
        }
        /**
         * Encodes all parameters.
         */
        encodeProperties() {
            const { search } = this.parser;
            const list = search.list();
            list.forEach((part, index) => {
                part.name = UrlEncoder.encodeQueryString(part.name, true);
                part.value = UrlEncoder.encodeQueryString(part.value, true);
                search.update(index, part);
            });
            // TODO: UrlEncoder.decodeQueryString(part, false) on each path segment
            this.requestUpdate();
            this.updateValue();
            if (this.text) {
                this.textValue = this.parser.search.toParamsString();
            }
        }
        /**
         * Decodes all parameters.
         */
        decodeProperties() {
            const { search } = this.parser;
            const list = search.list();
            list.forEach((part, index) => {
                part.name = UrlEncoder.decodeQueryString(part.name, true);
                part.value = UrlEncoder.decodeQueryString(part.value, true);
                search.update(index, part);
            });
            // TODO: UrlEncoder.encodeQueryString(part, false) on each path segment
            this.requestUpdate();
            this.updateValue();
            if (this.text) {
                this.textValue = this.parser.search.toParamsString();
            }
        }
        updateValue() {
            this.#value = this.parser.toString();
            this.notifyChange();
        }
        handleNameChange(e) {
            const input = e.target;
            const index = Number(input.dataset.index);
            if (Number.isNaN(index)) {
                return;
            }
            this.updateProperty(index, 'name', input.value);
            input.checkValidity();
        }
        handleValueChange(e) {
            const input = e.target;
            const index = Number(input.dataset.index);
            if (Number.isNaN(index)) {
                return;
            }
            this.updateProperty(index, 'value', input.value);
            input.checkValidity();
        }
        handleRemove(e) {
            const node = e.currentTarget;
            const index = Number(node.dataset.index);
            if (Number.isNaN(index)) {
                return;
            }
            this.removeProperty(index);
        }
        handleToggle(e) {
            const node = e.currentTarget;
            const index = Number(node.dataset.index);
            if (Number.isNaN(index)) {
                return;
            }
            this.toggleProperty(index, !!node.checked);
        }
        handleEncode() {
            this.encodeProperties();
        }
        handleDecode() {
            this.decodeProperties();
        }
        handleText(e) {
            const input = e.target;
            const { value } = input;
            this.parser.search.fromParamsString(value);
            this.updateValue();
        }
        render() {
            return html ` ${this.renderActionButtons()} ${this.renderEditor()} `;
        }
        renderActionButtons() {
            return html `
      <div class="editor-actions">
        <ui-button color="tonal" @click="${this.handleAdd}">Add</ui-button>
        <ui-button color="tonal" @click="${this.handleEncode}">URL encode</ui-button>
        <ui-button color="tonal" @click="${this.handleDecode}">URL decode</ui-button>
        <ui-dropdown-list @select="${this.handleOption}" closeOnOutsideClick class="dropdown">
          <ui-icon-button aria-label="Additional options"
            ><ui-icon icon="moreVert" role="presentation"></ui-icon
          ></ui-icon-button>
          <ui-list slot="dropdown" role="menu">
            <ui-list-item
              role="menuitem"
              data-option="text-editor"
              image="icon"
              title="Toggles between a text editor and a form"
            >
              <ui-icon role="presentation" slot="start" icon="${this.text ? 'checkBox' : 'checkBoxBlank'}"></ui-icon>
              Text editor
            </ui-list-item>
            <ui-divider type="inset"></ui-divider>
            <ui-list-item
              role="menuitem"
              data-option="clear"
              image="icon"
              title="Removes all parameters from the editor"
            >
              <ui-icon role="presentation" slot="start" icon="deleteOutline"></ui-icon>
              Clear form
            </ui-list-item>
          </ui-list>
        </ui-dropdown-list>
      </div>
    `;
        }
        renderEditor() {
            if (this.text) {
                return this.renderText();
            }
            return this.renderList();
        }
        renderText() {
            const { textValue = '' } = this;
            return html `
      <div class="text-input">
        <div class="error" role="presentation">Invalid character</div>
        <div class="state"></div>
        <textarea .value="${live(textValue)}" data-enable-grammarly="false" @change="${this.handleText}"></textarea>
      </div>
    `;
        }
        renderList() {
            const items = this.parser.search.list();
            if (!Array.isArray(items) || !items.length) {
                return this.renderEmptyMessage();
            }
            return this.renderParams(items);
        }
        renderEmptyMessage() {
            return html ` <div class="empty-message">No parameters added</div> `;
        }
        renderParams(items) {
            return html ` ${items.map((item, index) => this.renderParam(item, index))} `;
        }
        renderParam(item, index) {
            return html `
      <div class="param-row">
        ${this.renderToggleButton(item, index)} ${this.renderNameField(item, index)}
        ${this.renderValueField(item, index)} ${this.renderDeleteParameter(index)}
      </div>
    `;
        }
        renderToggleButton(item, index) {
            return html `
      <ui-switch
        .checked="${item.enabled}"
        @change="${this.handleToggle}"
        aria-label="Toggle this parameter"
        data-index="${index}"
        ?disabled="${this.readOnly}"
      ></ui-switch>
    `;
        }
        renderDeleteParameter(index) {
            return html `
      <ui-icon-button
        aria-label="Delete this parameter"
        data-index="${index}"
        @click="${this.handleRemove}"
        ?disabled="${this.readOnly}"
      >
        <ui-icon icon="deleteOutline" role="presentation"></ui-icon>
      </ui-icon-button>
    `;
        }
        renderNameField(item, index) {
            return html `
      <div class="input-wrapper name-input">
        <div class="error" role="presentation">Invalid character</div>
        <div class="state"></div>
        <input
          type="text"
          name="name"
          autocomplete="off"
          .value="${live(item.name)}"
          data-index="${index}"
          ?readOnly="${this.readOnly}"
          pattern="\\S*"
          aria-label="Parameter name value"
          @change="${this.handleNameChange}"
        />
      </div>
    `;
        }
        renderValueField(item, index) {
            return html `
      <div class="input-wrapper value-input">
        <div class="error" role="presentation">Invalid character</div>
        <div class="state"></div>
        <input
          type="text"
          name="value"
          .value="${live(item.value)}"
          data-index="${index}"
          ?readOnly="${this.readOnly}"
          pattern="\\S*"
          aria-label="Parameter value"
          @change="${this.handleValueChange}"
        />
      </div>
    `;
        }
        constructor() {
            super(...arguments);
            __runInitializers(this, _textValue_extraInitializers);
        }
    };
})();
export default UrlParamsForm;
//# sourceMappingURL=UrlParamsForm.js.map