import { h } from '@stencil/core';
import { LinkAnnotationAction } from '../../actions/link-annotation-action';
import { NodeAnnotationTypeEnum } from '../../annotations/node-annotation.abstract';
import { createEnterKeyHandlerToTriggerClick } from '../../../../../utils/accessibility';
import stateEntityRenderingRegistry from '../../../slimmers/controllers/state-entity-rendering-registry';
import { DomNodeSubjectObserverFactory } from '../../../../../helpers/change-manager/subject/dom-node-subject/dom-node-subject-observer-factory';
import { VegaChange } from '../../../../../helpers/event-manager/event-id/vega-event-id';
import RTETextNodeRenderer from '../nodes/text-node-renderer';
import { isNonNullable } from '../../../../../types/type-guard';
import { UnlinkLinkGroupAction } from '../../actions/unlink-link-group-action';
import RTEDTORendererManager from '../../../../../helpers/rte-manager/dto-renderer-manager';
/**
 * Renders link nodes and wraps them with link editor or anchor element based on edit mode.
 */
class RTELinkWrapperRenderer {
  constructor() {
    this.handleChange = ({ detail }, textFromNodes, linkNodes) => {
      switch (detail.action) {
        case 'link': {
          const { url, text } = detail.payload;
          const textChanged = text !== textFromNodes;
          linkNodes.forEach((node) => {
            const groupKey = node.getAnnotationByType(NodeAnnotationTypeEnum.LINK).link.groupKey;
            const linkAnnotationAction = new LinkAnnotationAction({
              link: { href: url, groupKey: groupKey },
              newText: textChanged ? text : undefined,
              needMergeNode: textChanged && linkNodes.length > 1,
              doSplit: false,
              type: 'update_link',
            });
            node.apply(linkAnnotationAction);
          });
          return;
        }
        case 'unlink': {
          linkNodes.forEach((node) => {
            node.parent.apply(new UnlinkLinkGroupAction(node.annotationMap.get(NodeAnnotationTypeEnum.LINK).link.groupKey));
            node.deleteAnnotationByType(NodeAnnotationTypeEnum.LINK);
          });
          return;
        }
      }
    };
  }
  /**
   * Render link nodes, grouping them by link group annotation if necessary.
   *
   * @param {RTETextNode[]} nodes - Array of text nodes to render.
   * @param {LinkGroupAnnotation} linkGroupAnnotation - link group annotation
   * @param {RTERenderContext} context - Context containing render options.
   * @returns {VegaRTERenderResult[]} - Array of rendered HTML elements.
   */
  render(nodes, linkGroupAnnotation, { editable }) {
    const blockNodes = this.groupNodesByLink(nodes);
    return blockNodes
      .flatMap((item) => {
      if (this.isLinkGroup(item)) {
        // TODO: should revert to above code while https://gethired.atlassian.net/browse/VD-6513 have be fixed.
        // 	const linkAnnotation: LinkAnnotation = item[0].getAnnotationByType<LinkAnnotation>(
        // 		NodeAnnotationTypeEnum.LINK,
        // 	) as LinkAnnotation;
        let linkAnnotation;
        item.find((node) => {
          const link = node.getAnnotationByType(NodeAnnotationTypeEnum.LINK);
          if (link) {
            linkAnnotation = link;
            return true;
          }
        });
        return editable
          ? this.renderLinkEditorWrapper(item, linkAnnotation, linkGroupAnnotation)
          : this.renderLink(item, linkAnnotation, linkGroupAnnotation);
      }
      const nodeRenderer = RTEDTORendererManager.getRTERenderer(item.type);
      if (nodeRenderer) {
        return nodeRenderer.render(item, { editable }, h);
      }
    })
      .filter(isNonNullable);
  }
  groupNodesByLink(nodes) {
    return nodes.reduce((acc, node) => {
      const nodeLinkAnnotation = node.getAnnotationByType(NodeAnnotationTypeEnum.LINK);
      const lastGroup = acc[acc.length - 1];
      if (isNonNullable(nodeLinkAnnotation)) {
        if (lastGroup &&
          this.isLinkGroup(lastGroup) &&
          lastGroup[0].getAnnotationByType(NodeAnnotationTypeEnum.LINK).toEqual(nodeLinkAnnotation)) {
          lastGroup.push(node);
        }
        else {
          acc.push([node]);
        }
      }
      else {
        acc.push(node);
      }
      return acc;
    }, []);
  }
  isLinkGroup(item) {
    return Array.isArray(item);
  }
  renderLinkEditorWrapper(linkNodes, linkAnnotation, linkGroupAnnotation) {
    const { href } = linkAnnotation.link;
    const textFromNodes = linkNodes.map((node) => node.text).join('');
    let linkWrapperRef;
    return (h("span", { class: "link-editor-wrapper", role: "link", tabIndex: 0, onKeyDown: createEnterKeyHandlerToTriggerClick(), ref: (ref) => {
        if (ref) {
          linkWrapperRef = ref;
          stateEntityRenderingRegistry.removeDirtyDomRef(ref);
        }
      } },
      this.renderLink(linkNodes, linkAnnotation, linkGroupAnnotation),
      h("vega-rich-text-link-editor", { record: {
          text: textFromNodes,
          url: href,
        }, ref: (ref) => {
          if (ref) {
            ref.target = linkWrapperRef;
            DomNodeSubjectObserverFactory.addUniqueObserverToNode(ref, VegaChange, (e) => {
              this.handleChange(e, textFromNodes, linkNodes);
            });
          }
        } })));
  }
  renderLink(linkNodes, linkAnnotation, linkGroupAnnotation) {
    return (h("a", Object.assign({}, linkGroupAnnotation.toJsx(linkAnnotation)), linkNodes.map((node) => RTETextNodeRenderer.render(node))));
  }
}
export default new RTELinkWrapperRenderer();
