import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
import { service } from "@ember/service";
import DButton from "discourse/components/d-button";
import virtualElementFromTextRange from "discourse/lib/virtual-element-from-text-range";
import eq from "truth-helpers/helpers/eq";
import AiPostHelperMenu from "../../components/ai-post-helper-menu";
import { showPostAIHelper } from "../../lib/show-ai-helper";

export default class AiPostHelperTrigger extends Component {
  static shouldRender(outletArgs, helper) {
    return showPostAIHelper(outletArgs, helper);
  }

  @service site;
  @service menu;

  @tracked menuState = this.MENU_STATES.triggers;
  @tracked showMainButtons = true;
  @tracked showAiButtons = true;
  @tracked originalPostHTML = null;
  @tracked postHighlighted = false;
  @tracked currentMenu = this.menu.getByIdentifier(
    "post-text-selection-toolbar"
  );

  MENU_STATES = {
    triggers: "TRIGGERS",
    options: "OPTIONS",
  };

  willDestroy() {
    super.willDestroy(...arguments);
    this.removeHighlightedText();
  }

  highlightSelectedText() {
    const postId = this.args.outletArgs.data.quoteState.postId;
    const postElement = document.querySelector(
      `article[data-post-id='${postId}'] .cooked`
    );

    if (!postElement) {
      return;
    }

    this.originalPostHTML = postElement.innerHTML;
    this.selectedText = this.args.outletArgs.data.quoteState.buffer;

    const selection = window.getSelection();
    if (!selection.rangeCount) {
      return;
    }

    const range = selection.getRangeAt(0);

    // Split start/end text nodes at their range boundary
    if (
      range.startContainer.nodeType === Node.TEXT_NODE &&
      range.startOffset > 0
    ) {
      const newStartNode = range.startContainer.splitText(range.startOffset);
      range.setStart(newStartNode, 0);
    }
    if (
      range.endContainer.nodeType === Node.TEXT_NODE &&
      range.endOffset < range.endContainer.length
    ) {
      range.endContainer.splitText(range.endOffset);
    }

    // Create a Walker to traverse text nodes within range
    const walker = document.createTreeWalker(
      range.commonAncestorContainer,
      NodeFilter.SHOW_TEXT,
      {
        acceptNode: (node) =>
          range.intersectsNode(node)
            ? NodeFilter.FILTER_ACCEPT
            : NodeFilter.FILTER_REJECT,
      }
    );

    const textNodes = [];

    if (walker.currentNode?.nodeType === Node.TEXT_NODE) {
      textNodes.push(walker.currentNode);
    } else {
      while (walker.nextNode()) {
        textNodes.push(walker.currentNode);
      }
    }

    for (let textNode of textNodes) {
      const highlight = document.createElement("span");
      highlight.classList.add("ai-helper-highlighted-selection");

      // Replace textNode with highlighted clone
      const clone = textNode.cloneNode(true);
      highlight.appendChild(clone);

      textNode.parentNode.replaceChild(highlight, textNode);
    }

    selection.removeAllRanges();
    this.postHighlighted = true;
  }

  removeHighlightedText() {
    if (!this.postHighlighted) {
      return;
    }

    const postId = this.args.outletArgs.data.quoteState.postId;
    const postElement = document.querySelector(
      `article[data-post-id='${postId}'] .cooked`
    );

    if (!postElement) {
      return;
    }

    postElement.innerHTML = this.originalPostHTML;
    this.postHighlighted = false;
  }

  @action
  async showAiPostHelperMenu() {
    this.highlightSelectedText();
    if (this.site.mobileView) {
      this.currentMenu.close();

      await this.menu.show(virtualElementFromTextRange(), {
        identifier: "ai-post-helper-menu",
        component: AiPostHelperMenu,
        inline: true,
        interactive: true,
        placement: this.shouldRenderUnder ? "bottom-start" : "top-start",
        fallbackPlacements: this.shouldRenderUnder
          ? ["bottom-end", "top-start"]
          : ["bottom-start"],
        trapTab: false,
        closeOnScroll: false,
        modalForMobile: true,
        data: this.menuData,
      });
    }

    this.showMainButtons = false;
    this.menuState = this.MENU_STATES.options;
  }

  get menuData() {
    // Streamline of data model to be passed to the component when
    // instantiated as a DMenu or a simple component in the template
    return {
      ...this.args.outletArgs.data,
      quoteState: {
        buffer: this.args.outletArgs.data.quoteState.buffer,
        opts: this.args.outletArgs.data.quoteState.opts,
        postId: this.args.outletArgs.data.quoteState.postId,
      },
      post: this.args.outletArgs.post,
      selectedText: this.selectedText,
    };
  }

  <template>
    {{#if this.showMainButtons}}
      {{yield}}
    {{/if}}

    {{#if this.showAiButtons}}
      <div class="ai-post-helper">
        {{#if (eq this.menuState this.MENU_STATES.triggers)}}
          <DButton
            @icon="discourse-sparkles"
            @title="discourse_ai.ai_helper.post_options_menu.title"
            @label="discourse_ai.ai_helper.post_options_menu.trigger"
            @action={{this.showAiPostHelperMenu}}
            class="btn-flat ai-post-helper__trigger"
          />

        {{else if (eq this.menuState this.MENU_STATES.options)}}
          <AiPostHelperMenu @data={{this.menuData}} />
        {{/if}}
      </div>
    {{/if}}
  </template>
}
