/**
 * @license
 * Copyright 2023 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

import {Bubble} from './bubble.js';
import {Coordinate} from '../utils/coordinate.js';
import * as dom from '../utils/dom.js';
import {Rect} from '../utils/rect.js';
import {Size} from '../utils/size.js';
import {Svg} from '../utils/svg.js';
import {WorkspaceSvg} from '../workspace_svg.js';

/**
 * A bubble that displays non-editable text. Used by the warning icon.
 */
export class TextBubble extends Bubble {
  private paragraph: SVGTextElement;

  constructor(
    private text: string,
    protected readonly workspace: WorkspaceSvg,
    protected anchor: Coordinate,
    protected ownerRect?: Rect,
  ) {
    super(workspace, anchor, ownerRect);
    this.paragraph = this.stringToSvg(text, this.contentContainer);
    this.updateBubbleSize();
  }

  /** @returns the current text of this text bubble. */
  getText(): string {
    return this.text;
  }

  /** Sets the current text of this text bubble, and updates the display. */
  setText(text: string) {
    this.text = text;
    dom.removeNode(this.paragraph);
    this.paragraph = this.stringToSvg(text, this.contentContainer);
    this.updateBubbleSize();
  }

  /**
   * Converts the given string into an svg containing that string,
   * broken up by newlines.
   */
  private stringToSvg(text: string, container: SVGGElement) {
    const paragraph = this.createParagraph(container);
    const spans = this.createSpans(paragraph, text);
    if (this.workspace.RTL)
      this.rightAlignSpans(paragraph.getBBox().width, spans);
    return paragraph;
  }

  /** Creates the paragraph container for this bubble's view's spans. */
  private createParagraph(container: SVGGElement): SVGTextElement {
    return dom.createSvgElement(
      Svg.TEXT,
      {
        'class': 'blocklyText blocklyBubbleText blocklyNoPointerEvents',
        'y': Bubble.BORDER_WIDTH,
      },
      container,
    );
  }

  /** Creates the spans visualizing the text of this bubble. */
  private createSpans(parent: SVGTextElement, text: string): SVGTSpanElement[] {
    return text.split('\n').map((line) => {
      const tspan = dom.createSvgElement(
        Svg.TSPAN,
        {'dy': '1em', 'x': Bubble.BORDER_WIDTH},
        parent,
      );
      const textNode = document.createTextNode(line);
      tspan.appendChild(textNode);
      return tspan;
    });
  }

  /** Right aligns the given spans. */
  private rightAlignSpans(maxWidth: number, spans: SVGTSpanElement[]) {
    for (const span of spans) {
      span.setAttribute('text-anchor', 'end');
      span.setAttribute('x', `${maxWidth + Bubble.BORDER_WIDTH}`);
    }
  }

  /** Updates the size of this bubble to account for the size of the text. */
  private updateBubbleSize() {
    const bbox = this.paragraph.getBBox();
    this.setSize(
      new Size(
        bbox.width + Bubble.BORDER_WIDTH * 2,
        bbox.height + Bubble.BORDER_WIDTH * 2,
      ),
      true,
    );
  }
}
