/**
 * Copyright Aquera Inc 2023
 *
 * This source code is licensed under the BSD-3-Clause license found in the
 * LICENSE file in the root directory of this source tree.
 */
import { __decorate } from "tslib";
import { html } from 'lit';
import { customElement, query, state, property } from 'lit/decorators.js';
import { styles } from './nile-content-editor.css';
import { classMap } from 'lit/directives/class-map.js';
import NileElement from '../internal/nile-element';
import { watch } from '../internal/watch';
import { KeyCode } from '../internal/enum';
import { live } from 'lit/directives/live.js';
/**
 * Nile icon component.
 *
 * @tag nile-attribute-expression
 *
 */
let NileContentEditor = class NileContentEditor extends NileElement {
    constructor() {
        /**
       * @summary Allows you to handle both input and dropdown selection
      
       * @dependency nile-option
       
       * @event nile-change - Emitted when the control's value changes.
       */
        super(...arguments);
        this.value = '';
        this.showLabel = true;
        this.labelText = '';
        this.type = 'text|text-area';
        this.required = true;
        this.openDropdown = false;
        this.tagIdentifier = '$';
        this.filteredValue = '';
        this.helpText = '';
        this.readonly = false;
        this.errorMessage = '';
        this.error = false;
        this.noborder = false;
        this.updateValue = false;
        this.initialValue = '';
        this.replaceText = '';
    }
    connectedCallback() {
        this.handleOutsideClick = this.handleOutsideClick.bind(this);
        this.handleClipboardEvent = this.handleClipboardEvent.bind(this);
        super.connectedCallback();
        this.emit('nile-init');
        this.addOpenListeners();
        this.setInitialValues();
    }
    addOpenListeners() {
        window.addEventListener('click', this.handleOutsideClick);
        this.addEventListener('cut', this.handleClipboardEvent);
        this.addEventListener('copy', this.handleClipboardEvent);
        this.addEventListener('paste', this.handleClipboardEvent);
    }
    removeOpenListeners() {
        this.removeEventListener('click', this.handleOutsideClick);
        this.removeEventListener('cut', this.handleClipboardEvent);
        this.removeEventListener('copy', this.handleClipboardEvent);
        this.removeEventListener('paste', this.handleClipboardEvent);
    }
    handleOutsideClick(event) {
        if (event && event.target && !this.contains(event.target)) {
            this.toggleDropdown(false);
        }
    }
    async handleClipboardEvent(event) {
        const selectedText = window?.getSelection()?.toString();
        switch (event.type) {
            case 'cut':
            case 'copy':
                if (!!selectedText)
                    await navigator.clipboard.writeText(selectedText);
                document.execCommand(event.type);
                break;
            case 'paste':
                event.preventDefault();
                let pastedText = '';
                pastedText = await navigator.clipboard.readText();
                pastedText = pastedText
                    .replace(/<(|\/)(html|body|meta|span)[^>]*?>/gi, '')
                    .trim();
                document.execCommand('insertText', false, pastedText);
                break;
            default:
                break;
        }
        setTimeout(() => {
            this.emitInputChange();
        });
    }
    toggleDropdown(value) {
        this.openDropdown = value;
    }
    setInitialValues() {
        this.updateComplete.then(res => {
            if (res)
                this.contentEditor.innerHTML = this.generateHTMLTagsWithValues(this.value);
        });
    }
    handleTypeChange() {
        if (this.updateValue) {
            this.contentEditor.innerHTML = this.generateHTMLTagsWithValues(this.value);
        }
    }
    disconnectedCallback() {
        super.disconnectedCallback();
        this.removeOpenListeners();
        this.emit('nile-destroy');
    }
    handlekeyDown(event) {
        if (event.code === KeyCode.ENTER && this.type === 'text') {
            event.preventDefault();
            return;
        }
        if ([KeyCode.CUT, KeyCode.COPY, KeyCode.PASTE].includes(event.code) &&
            (event.ctrlKey || event.metaKey)) {
            return;
        }
        if (event.code === KeyCode.ESCAPE) {
            event.preventDefault();
            this.toggleDropdown(false);
            return;
        }
        setTimeout(() => {
            const value = this.contentEditor.innerText;
            this.emitInputChange();
            if (value.includes(this.tagIdentifier)) {
                this.insertNodes(this.contentEditor, this.contentEditor.childNodes);
                this.filterOptions();
                this.toggleDropdown(true);
            }
            else {
                this.toggleDropdown(false);
            }
        }, 10);
    }
    filterOptions() {
        this.filteredOptions = this.options;
        this.filteredValue = this.filteredValue.trim();
        if (!!this.options.length && !!this.filteredValue) {
            this.filteredOptions = this.options.filter(item => item.includes(this.filteredValue));
        }
        else {
            this.filteredOptions = this.options;
        }
    }
    generateValuesFromHTMLTags(string) {
        let errorTag = /<span class="chips chip-error" contenteditable="false">(.*?)<\/span>/g;
        this.error = !!string.match(errorTag);
        var pattern = /<span class="chips(?: chip-error)?" contenteditable="false">(.*?)<\/span>/g;
        let result = string.replace(pattern, (match, option) => {
            return '{{' + option + '}}';
        });
        return result;
    }
    generateHTMLTagsWithValues(string) {
        var pattern = /{{(.*?)}}/g;
        var result = string.replace(pattern, (match, option) => {
            return this.options.includes(option)
                ? '<span class="chips" contenteditable="false">' + option + '</span>'
                : this.setError(option);
        });
        return result;
    }
    setError(option) {
        this.error = true;
        return ('<span class="chips chip-error" contenteditable="false">' +
            option +
            '</span>');
    }
    emitInputChange() {
        if (this.contentEditor) {
            let fieldValue = this.contentEditor.innerHTML;
            fieldValue = fieldValue.replace(/&nbsp;/g, ' ');
            fieldValue = fieldValue.replace('<br>', '');
            this.emit('nile-change', {
                value: this.generateValuesFromHTMLTags(fieldValue),
            });
        }
    }
    insertNodes(parentNode, childNodes, autoOptionsTag) {
        [...childNodes].forEach((node, index) => {
            if (node.hasChildNodes()) {
                if (autoOptionsTag) {
                    this.insertNodes(node, node.childNodes, autoOptionsTag);
                }
                else {
                    this.insertNodes(node, node.childNodes);
                }
            }
            else {
                if (node.nodeValue?.includes(this.tagIdentifier)) {
                    if (autoOptionsTag) {
                        this.insertAutoOptionsTag(node, autoOptionsTag);
                    }
                    this.setFilterValue(node.nodeValue);
                    return;
                }
            }
        });
    }
    insertAutoOptionsTag(node, autoOptionsTag) {
        const selection = window.getSelection();
        const range = document.createRange();
        const curssorNodeindex = node.nodeValue.indexOf(this.tagIdentifier);
        range.setStart(node, curssorNodeindex);
        range.insertNode(autoOptionsTag);
        range.setStartAfter(autoOptionsTag);
        range.collapse(true);
        selection?.removeAllRanges();
        selection?.addRange(range);
        if (autoOptionsTag.nextSibling?.nodeValue) {
            autoOptionsTag.nextSibling.nodeValue =
                autoOptionsTag.nextSibling?.nodeValue?.replace(this.tagIdentifier + this.filteredValue, '');
        }
        this.contentEditor.focus();
    }
    setFilterValue(value) {
        //replace Text - check if text exists after tagidentifier , if exists take account of that too
        if (!this.openDropdown) {
            this.replaceText = value.split(this.tagIdentifier).slice(1).join();
        }
        if (!!value && this.openDropdown) {
            this.filteredValue = value
                ?.split(this.tagIdentifier)
                .slice(1)
                .join()
                .replace(this.replaceText, '');
        }
        else {
            this.filteredValue = '';
        }
    }
    handleOptions(option) {
        this.toggleDropdown(false);
        let autoOptionsTag = document.createElement('span');
        autoOptionsTag.setAttribute('class', 'chips');
        autoOptionsTag.setAttribute('contentEditable', 'false');
        autoOptionsTag.innerText = option;
        this.insertNodes(this.contentEditor, this.contentEditor.childNodes, autoOptionsTag);
        this.resetOptions();
        this.emitInputChange();
    }
    resetOptions() {
        this.filteredOptions = this.options;
        this.filteredValue = '';
    }
    renderAutoOptions() {
        return html `<div
      class="${classMap({
            'nile-options-container': true,
            'dropdown-position': this.type === 'text-area',
        })}"
    >
      ${this.filteredOptions &&
            this.filteredOptions.map((option) => {
                return html ` <nile-option
          .value="${option}"
          @click="${(event) => {
                    this.handleOptions(option);
                }}"
          >${option}
        </nile-option>`;
            })}
    </div>`;
    }
    render() {
        const hasHelpText = this.helpText ? true : false;
        const hasError = !!this.error;
        const hasErrorMessage = !!this.errorMessage;
        const readonly = !!this.readonly;
        const noborder = !!this.noborder;
        const type = this.type;
        return html `
      <nile-popup
        .active="${live(this.openDropdown)}"
        sync="width"
        strategy="fixed"
        placement="bottom"
        class=${classMap({
            dropdown: true,
            'dropdown--open': true,
            popup: true,
        })}
      >
        <div class="content-editable-wrapper" slot="anchor">
          ${this.showLabel && this.labelText
            ? html `<label class="ods-label">${this.labelText} </label> ${this
                .required
                ? html `<span class="asterik">*</span>`
                : ''}`
            : ''}
          <div
            contenteditable="${!readonly}"
            spellcheck="false"
            class=${classMap({
            'content-editable-input': true,
            error: hasError || hasErrorMessage,
            'read-only': readonly,
            'no-border': noborder,
            'text-area': type === 'text-area' ? true : false,
        })}
            @keydown=${this.handlekeyDown}
          ></div>
          ${hasHelpText
            ? html `
                <nile-form-help-text>${this.helpText}</nile-form-help-text>
              `
            : ``}
          ${hasErrorMessage
            ? html `
                <nile-form-error-message
                  >${this.errorMessage}</nile-form-error-message
                >
              `
            : ``}
        </div>
        ${this.filteredOptions && !!this.filteredOptions.length
            ? this.renderAutoOptions()
            : null}
      </nile-popup>
    `;
    }
};
NileContentEditor.styles = styles;
__decorate([
    property()
], NileContentEditor.prototype, "value", void 0);
__decorate([
    property()
], NileContentEditor.prototype, "options", void 0);
__decorate([
    property()
], NileContentEditor.prototype, "filteredOptions", void 0);
__decorate([
    property()
], NileContentEditor.prototype, "showLabel", void 0);
__decorate([
    property()
], NileContentEditor.prototype, "labelText", void 0);
__decorate([
    property()
], NileContentEditor.prototype, "type", void 0);
__decorate([
    property()
], NileContentEditor.prototype, "required", void 0);
__decorate([
    query('.content-editable-input')
], NileContentEditor.prototype, "contentEditor", void 0);
__decorate([
    query('.nile-options-container')
], NileContentEditor.prototype, "autoOptions", void 0);
__decorate([
    state()
], NileContentEditor.prototype, "openDropdown", void 0);
__decorate([
    property({ attribute: 'help-text' })
], NileContentEditor.prototype, "helpText", void 0);
__decorate([
    property({ attribute: 'readonly' })
], NileContentEditor.prototype, "readonly", void 0);
__decorate([
    property({ attribute: 'error-message' })
], NileContentEditor.prototype, "errorMessage", void 0);
__decorate([
    property({ attribute: 'error' })
], NileContentEditor.prototype, "error", void 0);
__decorate([
    property({ attribute: 'noborder' })
], NileContentEditor.prototype, "noborder", void 0);
__decorate([
    property({ type: Boolean })
], NileContentEditor.prototype, "updateValue", void 0);
__decorate([
    state()
], NileContentEditor.prototype, "initialValue", void 0);
__decorate([
    watch(['type', 'value'], { waitUntilFirstUpdate: true })
], NileContentEditor.prototype, "handleTypeChange", null);
NileContentEditor = __decorate([
    customElement('nile-content-editor')
], NileContentEditor);
export { NileContentEditor };
export default NileContentEditor;
//# sourceMappingURL=nile-content-editor.js.map