import { h, Host } from '@stencil/core';
import { KeyboardManager, ObjectUtils } from '@sankhyalabs/core';
import { RICH_TOOLBAR_COMMANDS, RICH_TOOLBAR_FORMAT_TAGS, } from './ez-rich-toolbar/RichToolbarHelper';
import DOMPurify from 'dompurify';
import initI18n from '../../utils/i18n';
export class EzRichText {
  constructor() {
    this.historyStack = [];
    this.historyIndex = -1;
    this.previewMode = false;
    this.showPreview = true;
    this.value = '';
    this.label = undefined;
    this.mode = "regular";
    this.enabled = true;
    this.rows = 6;
    this.errorMessage = undefined;
    this.canShowError = true;
    this.showConfigs = true;
    this.showTextFormat = true;
    this.showUndoRedo = true;
  }
  observeValue(newValue, oldValue) {
    if (ObjectUtils.equals(newValue, oldValue))
      return;
    this.ezChange.emit(newValue);
  }
  observeErrorMessage(newValue) {
    if (newValue && this.previewMode) {
      this.previewMode = false;
    }
  }
  async handleExecuteToolbarCommand(event) {
    const { command, value } = event.detail;
    await this.executeCommand(command, value);
  }
  /**
   * Aplica o foco no campo.
   */
  async setFocus() {
    this.handleFocus();
  }
  /**
   * Remove o foco do campo.
   */
  async setBlur() {
    var _a;
    await ((_a = this.textAreaRef) === null || _a === void 0 ? void 0 : _a.setBlur());
  }
  /**
   * Retorna se o conteúdo é inválido.
   */
  async isInvalid() {
    return typeof this.errorMessage === 'string' && this.errorMessage.trim() !== '';
  }
  bindPreview() {
    if (!this._keyboardManager || !this.showPreview)
      return;
    this._keyboardManager
      .bind('ctrl + p', async () => {
      await this.togglePreview();
    }, { description: 'Entra em modo de pré visualização.', element: this.element });
  }
  bindConfigs() {
    if (!this._keyboardManager || !this.showConfigs)
      return;
    this._keyboardManager
      .bind('ctrl + l', async () => {
      await this.handleFormatSelection(RICH_TOOLBAR_FORMAT_TAGS.LIST);
    }, { description: this.i18n("ez-rich-text.listShortcut"), element: this.element })
      .bind('ctrl + k', async () => {
      await this.handleLink();
    }, { description: this.i18n("ez-rich-text.linkShortcut"), element: this.element })
      .bind('ctrl + o', async () => {
      await this.handleImage();
    }, { description: this.i18n("ez-rich-text.imageShortcut"), element: this.element });
  }
  bindTextFormat() {
    if (!this._keyboardManager || !this.showTextFormat)
      return;
    this._keyboardManager
      .bind('ctrl + b', async () => {
      await this.handleFormatSelection(RICH_TOOLBAR_FORMAT_TAGS.BOLD);
    }, { description: this.i18n("ez-rich-text.boldShortcut"), element: this.element })
      .bind('ctrl + i', async () => {
      await this.handleFormatSelection(RICH_TOOLBAR_FORMAT_TAGS.ITALIC);
    }, { description: this.i18n("ez-rich-text.italicShortcut"), element: this.element })
      .bind('ctrl + u', async () => {
      await this.handleFormatSelection(RICH_TOOLBAR_FORMAT_TAGS.UNDERLINE);
    }, { description: this.i18n("ez-rich-text.underlineShortcut"), element: this.element });
  }
  initKeyboardManager() {
    this._keyboardManager = new KeyboardManager({ propagate: false, element: this.element });
    this._keyboardManager
      .bind('ctrl + Enter', async () => {
      await this.handleFormatSelection(RICH_TOOLBAR_FORMAT_TAGS.BREAK_LINE);
    }, { description: this.i18n("ez-rich-text.breakLineShortcut"), element: this.element })
      .bind('ctrl + z', async () => {
      await this.handleUndo();
    }, { description: this.i18n("ez-rich-text.undoShortcut"), element: this.element })
      .bind('ctrl + x', async () => {
      await this.handleRedo();
    }, { description: this.i18n("ez-rich-text.redoShortcut"), element: this.element });
    this.bindPreview();
    this.bindConfigs();
    this.bindTextFormat();
  }
  async executeCommand(command, value) {
    switch (command) {
      case RICH_TOOLBAR_COMMANDS.FOCUS:
        this.handleFocus();
        break;
      case RICH_TOOLBAR_COMMANDS.PREVIEW:
        await this.togglePreview();
        break;
      case RICH_TOOLBAR_COMMANDS.FORMAT:
        await this.handleFormatSelection(value);
        break;
      case RICH_TOOLBAR_COMMANDS.UNDO:
        await this.handleUndo();
        break;
      case RICH_TOOLBAR_COMMANDS.REDO:
        await this.handleRedo();
        break;
      case RICH_TOOLBAR_COMMANDS.LINK:
        await this.handleLink();
        break;
      case RICH_TOOLBAR_COMMANDS.IMAGE:
        await this.handleImage();
        break;
    }
  }
  handleFocus() {
    this.previewMode = false;
    requestAnimationFrame(async () => {
      await this.textAreaRef.setFocus();
    });
  }
  async handleLink() {
    this.previewMode = false;
    requestAnimationFrame(async () => {
      await this.linkBuilderRef.show(this.getSelectedText());
    });
  }
  async handleImage() {
    this.previewMode = false;
    await this.imageUploaderRef.show();
  }
  async handleRedo() {
    this.previewMode = false;
    requestAnimationFrame(async () => {
      this.redo();
      await this.textAreaRef.setFocus();
    });
  }
  async handleUndo() {
    this.previewMode = false;
    requestAnimationFrame(async () => {
      this.undo();
      await this.textAreaRef.setFocus();
    });
  }
  async handleFormatSelection(value) {
    if (!value)
      return;
    this.previewMode = false;
    requestAnimationFrame(async () => {
      await this.formatSelection(value);
      await this.textAreaRef.setFocus();
    });
  }
  async togglePreview() {
    this.previewMode = !this.previewMode;
    if (this.previewMode) {
      await this.textAreaRef.setFocus();
    }
  }
  getSelectedText() {
    const textarea = this.getTextAreaElement();
    if (!textarea)
      return undefined;
    const selectionStart = textarea.selectionStart;
    const selectionEnd = textarea.selectionEnd;
    const currentValue = this.textAreaRef.value || '';
    return currentValue.substring(selectionStart, selectionEnd);
  }
  getTextAreaElement() {
    const textAreaElement = this.element.querySelector('ez-text-area');
    return textAreaElement.shadowRoot.querySelector('textarea');
  }
  async formatSelection(htmlTag) {
    if (!this.textAreaRef)
      return;
    const formattedHtml = htmlTag.replace('$selection', this.getSelectedText() || '');
    await this.textAreaRef.appendTextToSelection(formattedHtml);
    this.value = this.textAreaRef.value;
    this.addToHistory(this.value);
  }
  addToHistory(content) {
    // Só adiciona ao histórico se for diferente do estado atual
    if (this.historyIndex >= 0 && content === this.historyStack[this.historyIndex]) {
      return;
    }
    //se o tamanho do histórico chegou ao máximo, faz um splice mantendo os últimos 49 elementos
    if (this.historyStack.length >= 50) {
      this.historyStack.splice(0, this.historyStack.length - 49);
    }
    //Adiciona novo estado ao histórico
    this.historyStack.push(content);
    this.historyIndex = this.historyStack.length - 1;
  }
  undo() {
    if (!this.canExecuteUndo())
      return;
    this.historyIndex--;
    const content = this.historyStack[this.historyIndex];
    this.value = content;
    this.textAreaRef.value = content;
  }
  canExecuteUndo() {
    return this.historyIndex > 0;
  }
  redo() {
    if (!this.canExecuteRedo())
      return;
    this.historyIndex++;
    this.getValueFromHistory();
  }
  canExecuteRedo() {
    return this.historyIndex < this.historyStack.length - 1;
  }
  getValueFromHistory() {
    const content = this.historyStack[this.historyIndex];
    this.value = content;
    this.textAreaRef.value = content;
  }
  handleTextAreaChanged(event) {
    this.value = event.detail;
    this.addToHistory(this.value);
  }
  async removeShortcuts() {
    var _a;
    (_a = this._keyboardManager) === null || _a === void 0 ? void 0 : _a.unbindAllShortcutKeys();
  }
  async componentWillLoad() {
    this.i18n = await initI18n();
  }
  componentDidLoad() {
    this.initKeyboardManager();
    this.addToHistory(this.value);
  }
  async disconnectedCallback() {
    await this.removeShortcuts();
  }
  getSanitizedValue() {
    return DOMPurify.sanitize(this.value, {
      ADD_ATTR: ['target', 'rel']
    });
  }
  renderContent() {
    if (this.previewMode) {
      return (h("div", { id: 'rich-text-preview-container', class: "preview", innerHTML: this.getSanitizedValue() }));
    }
    return h("ez-text-area", { ref: (el) => this.textAreaRef = el, label: this.label, value: this.value, enabled: this.enabled, rows: this.rows, mode: this.mode, canShowError: this.canShowError, errorMessage: this.errorMessage, onEzChange: this.handleTextAreaChanged.bind(this) });
  }
  render() {
    return (h(Host, null, h("div", { class: 'editor-container bordered' }, h("ez-rich-toolbar", { isPreviewMode: this.previewMode, showPreview: this.showPreview, showConfigs: this.showConfigs && this.enabled, showTextFormat: this.showTextFormat && this.enabled, showUndoRedo: this.showUndoRedo && this.enabled }), this.renderContent()), h("ez-link-builder", { ref: (el) => this.linkBuilderRef = el }), h("ez-simple-image-uploader", { ref: (el) => this.imageUploaderRef = el })));
  }
  static get is() { return "ez-rich-text"; }
  static get encapsulation() { return "scoped"; }
  static get originalStyleUrls() {
    return {
      "$": ["ez-rich-text.css"]
    };
  }
  static get styleUrls() {
    return {
      "$": ["ez-rich-text.css"]
    };
  }
  static get properties() {
    return {
      "showPreview": {
        "type": "boolean",
        "mutable": false,
        "complexType": {
          "original": "boolean",
          "resolved": "boolean",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Informa se as op\u00E7\u00F5es a op\u00E7\u00E3o de pr\u00E9-visualiza\u00E7\u00E3o deve ser apresentada."
        },
        "attribute": "show-preview",
        "reflect": false,
        "defaultValue": "true"
      },
      "value": {
        "type": "string",
        "mutable": true,
        "complexType": {
          "original": "string",
          "resolved": "string",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Define o valor HTML do campo."
        },
        "attribute": "value",
        "reflect": true,
        "defaultValue": "''"
      },
      "label": {
        "type": "string",
        "mutable": false,
        "complexType": {
          "original": "string",
          "resolved": "string",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Texto a ser apresentado como t\u00EDtulo do campo."
        },
        "attribute": "label",
        "reflect": true
      },
      "mode": {
        "type": "string",
        "mutable": false,
        "complexType": {
          "original": "\"slim\" | \"regular\"",
          "resolved": "\"regular\" | \"slim\"",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Define o tamanho do campo."
        },
        "attribute": "mode",
        "reflect": true,
        "defaultValue": "\"regular\""
      },
      "enabled": {
        "type": "boolean",
        "mutable": false,
        "complexType": {
          "original": "boolean",
          "resolved": "boolean",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Se false o usu\u00E1rio n\u00E3o pode interagir com o campo."
        },
        "attribute": "enabled",
        "reflect": true,
        "defaultValue": "true"
      },
      "rows": {
        "type": "number",
        "mutable": false,
        "complexType": {
          "original": "number",
          "resolved": "number",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Define o n\u00FAmero de linhas."
        },
        "attribute": "rows",
        "reflect": true,
        "defaultValue": "6"
      },
      "errorMessage": {
        "type": "string",
        "mutable": true,
        "complexType": {
          "original": "string",
          "resolved": "string",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Define uma mensagem de orienta\u00E7\u00E3o ao usu\u00E1rio, colocando o campo em modo inv\u00E1lido."
        },
        "attribute": "error-message",
        "reflect": true
      },
      "canShowError": {
        "type": "boolean",
        "mutable": false,
        "complexType": {
          "original": "boolean",
          "resolved": "boolean",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Se false deixa de exibir a mensagem de erro dentro do campo."
        },
        "attribute": "can-show-error",
        "reflect": true,
        "defaultValue": "true"
      },
      "showConfigs": {
        "type": "boolean",
        "mutable": false,
        "complexType": {
          "original": "boolean",
          "resolved": "boolean",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Informa se as op\u00E7\u00F5es de configura\u00E7\u00F5es (lista, imagem e link) devem ser apresentadas"
        },
        "attribute": "show-configs",
        "reflect": false,
        "defaultValue": "true"
      },
      "showTextFormat": {
        "type": "boolean",
        "mutable": false,
        "complexType": {
          "original": "boolean",
          "resolved": "boolean",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Informa se as op\u00E7\u00F5es de formata\u00E7\u00E3o de texto (it\u00E1lico, sublinhado e negrito) devem ser apresentadas"
        },
        "attribute": "show-text-format",
        "reflect": false,
        "defaultValue": "true"
      },
      "showUndoRedo": {
        "type": "boolean",
        "mutable": false,
        "complexType": {
          "original": "boolean",
          "resolved": "boolean",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Informa se as op\u00E7\u00F5es de desfazer e refazer devem ser habilitadas."
        },
        "attribute": "show-undo-redo",
        "reflect": false,
        "defaultValue": "true"
      }
    };
  }
  static get states() {
    return {
      "previewMode": {}
    };
  }
  static get events() {
    return [{
        "method": "ezChange",
        "name": "ezChange",
        "bubbles": true,
        "cancelable": true,
        "composed": true,
        "docs": {
          "tags": [],
          "text": "Emitido quando acontece a altera\u00E7\u00E3o de valor do campo."
        },
        "complexType": {
          "original": "string",
          "resolved": "string",
          "references": {}
        }
      }];
  }
  static get methods() {
    return {
      "setFocus": {
        "complexType": {
          "signature": "() => Promise<void>",
          "parameters": [],
          "references": {
            "Promise": {
              "location": "global"
            }
          },
          "return": "Promise<void>"
        },
        "docs": {
          "text": "Aplica o foco no campo.",
          "tags": []
        }
      },
      "setBlur": {
        "complexType": {
          "signature": "() => Promise<void>",
          "parameters": [],
          "references": {
            "Promise": {
              "location": "global"
            }
          },
          "return": "Promise<void>"
        },
        "docs": {
          "text": "Remove o foco do campo.",
          "tags": []
        }
      },
      "isInvalid": {
        "complexType": {
          "signature": "() => Promise<boolean>",
          "parameters": [],
          "references": {
            "Promise": {
              "location": "global"
            }
          },
          "return": "Promise<boolean>"
        },
        "docs": {
          "text": "Retorna se o conte\u00FAdo \u00E9 inv\u00E1lido.",
          "tags": []
        }
      }
    };
  }
  static get elementRef() { return "element"; }
  static get watchers() {
    return [{
        "propName": "value",
        "methodName": "observeValue"
      }, {
        "propName": "errorMessage",
        "methodName": "observeErrorMessage"
      }];
  }
  static get listeners() {
    return [{
        "name": "executeToolbarCommand",
        "method": "handleExecuteToolbarCommand",
        "target": undefined,
        "capture": false,
        "passive": false
      }];
  }
}
