import { __decorate } from "tslib";
import { css, html } from "lit";
import { property, state } from "lit/decorators.js";
import { live } from "lit/directives/live.js";
import { EventUtils } from "@api-client/core/build/browser.js";
import ApiElement from "../ApiElement.js";
import EditorCommon from './CommonStyles.js';
import theme from '../theme.js';
import typography from "../../styles/m3/typography.module.js";
import '../../define/ui/ui-text-field.js';
import '../../define/ui/ui-checkbox.js';
import '../../define/ui/ui-divider.js';
import '../../define/ui/ui-icon-button.js';
import '../../define/ui/ui-icon.js';
/**
 * An editor for a data entity.
 *
 * @fires change - When the entity has changed.
 * @fires namechange - When a name of the entity has changed.
 */
export default class EntityFormElement extends ApiElement {
    static get styles() {
        return [
            theme,
            EditorCommon,
            typography,
            css `
      :host {
        display: block;
      }

      .no-info {
        margin: 12px 20px;
      }

      .parents-list {
        margin: 0;
        padding: 0;
      }

      .parent-item {
        list-style: none;
        height: var(--list-item-height, 40px);
        display: flex;
        align-items: center;
        padding: 0 20px;
      }

      .parent-item.two-line {
        height: var(--list-item-two-line-height);
      }

      .parent-item-wrapper {
        flex: 1;
      }
      `
        ];
    }
    willUpdate(cp) {
        if (cp.has('key')) {
            this._computeEntity();
        }
    }
    /**
     * Adds a parent entity to this entity.
     * @param parentKey The key of the parent to add.
     */
    addParent(parentKey) {
        const { key, _entity } = this;
        if (!parentKey || parentKey === key || !_entity) {
            return;
        }
        if (!_entity.parents.includes(parentKey)) {
            _entity.parents.push(parentKey);
        }
        this.notifyChange();
    }
    /**
     * Computes the view value for the property.
     * This should be called before the update is complete so this won't trigger another update.
     */
    _computeEntity() {
        const { root, key } = this;
        if (!root || !key) {
            this._entity = undefined;
            return;
        }
        this._entity = root.definitions.entities.find(i => i.key === key);
    }
    _infoChangeHandler(e) {
        const { _entity } = this;
        if (!_entity) {
            return;
        }
        const node = e.target;
        const { name, value } = node;
        if (!['name', 'displayName', 'description'].includes(name)) {
            return;
        }
        if (name === 'name' && !value) {
            return;
        }
        _entity.info[name] = value;
        this.notifyChange();
        if (name === 'name' || name === 'displayName') {
            this.dispatchEvent(new Event('namechange'));
        }
    }
    _checkedHandler(e) {
        const { _entity } = this;
        if (!_entity) {
            return;
        }
        const input = e.target;
        const name = input.name;
        const { checked } = input;
        if (_entity[name] === checked) {
            return;
        }
        _entity[name] = checked;
        this.notifyChange();
        this.requestUpdate();
    }
    _dragoverHandler(e) {
        const { dataTransfer } = e;
        if (!dataTransfer) {
            return;
        }
        e.preventDefault();
        e.preventDefault();
        dataTransfer.dropEffect = "copy";
    }
    _dropHandler(e) {
        const { dataTransfer } = e;
        if (!dataTransfer) {
            return;
        }
        const node = e.target;
        const { type } = node.dataset;
        if (type === 'entity-parent') {
            e.preventDefault();
            this.parentDropZone = false;
            const key = dataTransfer.getData('text/key');
            this.addParent(key);
        }
    }
    _parentRemoveHandler(e) {
        const node = e.currentTarget;
        if (node.dataset.key) {
            this.removeParent(node.dataset.key);
        }
    }
    /**
     * Removes a parent with the given key.
     * @param key The key of the parent to remove.
     */
    removeParent(key) {
        const { _entity } = this;
        if (!key || !_entity) {
            return;
        }
        const index = _entity.parents.indexOf(key);
        if (index < 0) {
            return;
        }
        _entity.parents.splice(index, 1);
        this.notifyChange();
        this.requestUpdate();
    }
    render() {
        const { _entity: item } = this;
        if (!item) {
            return html ``;
        }
        const { info, deprecated = false } = item;
        return html `
    <form name="entity" @submit="${EventUtils.cancelEvent}" data-key="${item.key}">
      <ui-text-field class="input" name="name" .value="${live(info.name || '')}" label="Entity name" required @change="${this._infoChangeHandler}"></ui-text-field>
      <ui-text-field class="input" name="displayName" .value="${live(info.displayName || '')}" label="Display name (optional)" @change="${this._infoChangeHandler}"></ui-text-field>
      <ui-text-field class="input" name="description" .value="${live(info.description || '')}" label="Entity description (optional)" @change="${this._infoChangeHandler}"></ui-text-field>

      <div class="checkbox-group">
        <label class="label-large">
          <ui-checkbox name="deprecated" .checked="${deprecated}" title="Makes this entity deprecated." @change="${this._checkedHandler}"></ui-checkbox>
          Deprecated
        </label>
      </div>

      ${this._parentsEditorTemplate(item)}
    </form>
    `;
    }
    _parentsEditorTemplate(entity) {
        return html `
    <ui-divider type="full"></ui-divider>
    <div class="editor-title title-medium">Parents</div>
    ${this.parentDropZone ? this._parentDropZoneTemplate() : this._parentsTemplate(entity)}
    `;
    }
    _parentDropZoneTemplate() {
        return html `<div 
      class="drop-zone" 
      data-type="entity-parent" 
      @dragover="${this._dragoverHandler}" 
      @drop="${this._dropHandler}">
      Drop a parent entity here.
    </div>`;
    }
    _parentsTemplate(entity) {
        const parents = entity.getComputedParents();
        return html `
    ${parents.length ? this._parentsListTemplate(parents) : this.renderEmptyParentsMessage()}
    `;
    }
    renderEmptyParentsMessage() {
        return html `
      <p class="no-description no-info body-medium">No parent entities. You can drop an entity here to create an association.</p>
    `;
    }
    _parentsListTemplate(parents) {
        return html `
    <ul class="parents-list">
      ${parents.map(p => this._parentItemTemplate(p))}
    </ul>
    `;
    }
    _parentItemTemplate(item) {
        const parent = item.getParent();
        const label = item.info.name || item.key;
        return html `
    <li class="parent-item${parent ? ' two-line' : ''}" data-key="${item.key}">
      <div class="parent-item-wrapper">
        <span class="parent-label">${label}</span>
        ${parent ? html `<div class="secondary">From data model: ${parent.info.name}</div>` : ''}
      </div>
      <ui-icon-button aria-label="Remove this parent" title="Removes this parent" data-key="${item.key}" @click="${this._parentRemoveHandler}">
        <ui-icon icon="deleteOutline" role="presentation"></ui-icon>
      </ui-icon-button>
    </li>
    `;
    }
}
__decorate([
    property({ type: String, reflect: true })
], EntityFormElement.prototype, "key", void 0);
__decorate([
    property({ type: Object })
], EntityFormElement.prototype, "root", void 0);
__decorate([
    property({ type: Boolean })
], EntityFormElement.prototype, "parentDropZone", void 0);
__decorate([
    state()
], EntityFormElement.prototype, "_entity", void 0);
//# sourceMappingURL=EntityFormElement.js.map