import ProseMirrorMenu from "../menu.mjs";
import {serializeHTMLString} from "../util.mjs";
import {PluginKey} from "prosemirror-state";
import ChatInputPlugin from "./chat-input-plugin.mjs";

/**
 * A ProseMirror menu implementation specialized for the chat editor.
 * @extends {ProseMirrorMenu}
 */
export default class ChatMenuPlugin extends ProseMirrorMenu {
  /** @override */
  static key = new PluginKey(this.name);

  /* -------------------------------------------- */
  /*  Methods                                     */
  /* -------------------------------------------- */

  /** @inheritDoc */
  render() {
    super.render();
    this.view.dom.closest(".editor").querySelector("menu .format [data-action=insert]").hidden = true;
    return this;
  }

  /* -------------------------------------------- */

  /** @inheritDoc */
  _getMenuItems() {
    const items = super._getMenuItems();
    for ( const item of items ) {
      switch ( item.action ) {
        // Always show these items.
        case "horizontal-rule": case "image": case "link":
          delete item.weight;
          break;

        case "source-code":
          item.cmd = this._editSource.bind(this);
          break;
      }
    }
    return items;
  }

  /* -------------------------------------------- */

  /**
   * Spawn a dialog for editing the message's source HTML.
   * @protected
   */
  _editSource() {
    const dialog = new foundry.applications.api.DialogV2({
      content: '<code-mirror language="html"></code-mirror>',
      modal: true,
      position: {
        width: 800,
        height: 600
      },
      window: {
        contentClasses: ["flexcol"],
        icon: "fa-solid fa-code",
        resizable: true
      },
      buttons: [{
        action: "send",
        label: "CHAT.SendMessage",
        icon: "fa-solid fa-arrow-down-to-bracket",
        type: "button",
        callback: this.#sendMessage.bind(this)
      }, {
        action: "save",
        label: "EDITOR.Save",
        icon: "fa-regular fa-floppy-disk",
        type: "submit",
        default: true,
        callback: this.#saveMarkup.bind(this)
      }]
    });
    dialog.addEventListener("render", event => {
      const { element } = event.target;
      element.querySelector(".dialog-form").classList.add("flexcol", "flex1");
      element.querySelector(".dialog-content").classList.add("flex1");
      element.querySelector("code-mirror").value = serializeHTMLString(this.view.state.doc.content, { spaces: 4 });
    });
    dialog.addEventListener("close", () => this.view.focus());
    dialog.render({ force: true });
  }

  /* -------------------------------------------- */

  /**
   * Handle saving the edited source markup.
   * @param {SubmitEvent} event         The dialog submission event.
   * @param {HTMLButtonElement} button  The button that was clicked.
   * @param {DialogV2} dialog           The dialog instance.
   */
  #saveMarkup(event, button, dialog) {
    const editor = dialog.element.querySelector("code-mirror");
    this.#getChatInput().setMessage(this.view, editor.value);
  }

  /* -------------------------------------------- */

  /**
   * Handle sending a chat message directly from the markup editor.
   * @param {SubmitEvent} event         The dialog submission event.
   * @param {HTMLButtonElement} button  The button that was clicked.
   * @param {DialogV2} dialog           The dialog content.
   * @returns {Promise<void>}
   */
  #sendMessage(event, button, dialog) {
    this.#saveMarkup(event, button, dialog);
    return this.#getChatInput().sendMessage(this.view);
  }

  /* -------------------------------------------- */
  /*  Helpers                                     */
  /* -------------------------------------------- */

  /**
   * Retrieve the chat input plugin instance from the view state.
   * @returns {ChatInputPlugin}
   */
  #getChatInput() {
    return ChatInputPlugin.key.get(this.view.state).spec.instance;
  }
}
