import {
  escapeHtml,
  replaceEntities,
  unescapeMd,
} from "remarkable/lib/common/utils";
import { Remarkable } from "remarkable";
import { UiLogicError } from "@/common";
import { base64 } from "@/http/common";
import { HttpTimelinePostPostRequest } from "@/http/timeline";
export class TimelinePostBuilder {
  private _onChange: () => void;
  private _text = "";
  private _images: { file: File; url: string }[] = [];
  private _md: Remarkable = new Remarkable();
  constructor(onChange: () => void) {
    this._onChange = onChange;
    this._md.renderer.rules.image = ((
      _t: TimelinePostBuilder
    ): Remarkable.Rule =>
      function (tokens, idx, options /*, env */) {
        const i = parseInt(tokens[idx].src);
        const src =
          ' src="' +
          (isNaN(i) && i > 0 && i <= _t._images.length
            ? escapeHtml(tokens[idx].src)
            : _t._images[i - 1].url) +
          '"';
        const title = tokens[idx].title
          ? ' title="' + escapeHtml(replaceEntities(tokens[idx].title)) + '"'
          : "";
        const alt =
          ' alt="' +
          (tokens[idx].alt
            ? escapeHtml(replaceEntities(unescapeMd(tokens[idx].alt)))
            : "") +
          '"';
        const suffix = options?.xhtmlOut ? " /" : "";
        return "![]() ";
      })(this);
  }
  setMarkdownText(text: string): void {
    this._text = text;
    this._onChange();
  }
  appendImage(file: File): void {
    this._images.push({
      file,
      url: URL.createObjectURL(file),
    });
    this._onChange();
  }
  moveImage(oldIndex: number, newIndex: number): void {
    if (oldIndex < 0 || oldIndex >= this._images.length) {
      throw new UiLogicError("Old index out of range.");
    }
    if (newIndex < 0) {
      newIndex = 0;
    }
    if (newIndex >= this._images.length) {
      newIndex = this._images.length - 1;
    }
    const [old] = this._images.splice(oldIndex, 1);
    this._images.splice(newIndex, 0, old);
    this._onChange();
  }
  deleteImage(index: number): void {
    if (index < 0 || index >= this._images.length) {
      throw new UiLogicError("Old index out of range.");
    }
    URL.revokeObjectURL(this._images[index].url);
    this._images.splice(index, 1);
    this._onChange();
  }
  get images(): { file: File; url: string }[] {
    return this._images;
  }
  renderHtml(): string {
    return this._md.render(this._text);
  }
  dispose(): void {
    for (const image of this._images) {
      URL.revokeObjectURL(image.url);
    }
    this._images = [];
  }
  async build(): Promise {
    return [
      {
        contentType: "text/markdown",
        data: await base64(this._text),
      },
      ...(await Promise.all(
        this._images.map((image) =>
          base64(image.file).then((data) => ({
            contentType: image.file.type,
            data,
          }))
        )
      )),
    ];
  }
}
";
      })(this);
  }
  setMarkdownText(text: string): void {
    this._text = text;
    this._onChange();
  }
  appendImage(file: File): void {
    this._images.push({
      file,
      url: URL.createObjectURL(file),
    });
    this._onChange();
  }
  moveImage(oldIndex: number, newIndex: number): void {
    if (oldIndex < 0 || oldIndex >= this._images.length) {
      throw new UiLogicError("Old index out of range.");
    }
    if (newIndex < 0) {
      newIndex = 0;
    }
    if (newIndex >= this._images.length) {
      newIndex = this._images.length - 1;
    }
    const [old] = this._images.splice(oldIndex, 1);
    this._images.splice(newIndex, 0, old);
    this._onChange();
  }
  deleteImage(index: number): void {
    if (index < 0 || index >= this._images.length) {
      throw new UiLogicError("Old index out of range.");
    }
    URL.revokeObjectURL(this._images[index].url);
    this._images.splice(index, 1);
    this._onChange();
  }
  get images(): { file: File; url: string }[] {
    return this._images;
  }
  renderHtml(): string {
    return this._md.render(this._text);
  }
  dispose(): void {
    for (const image of this._images) {
      URL.revokeObjectURL(image.url);
    }
    this._images = [];
  }
  async build(): Promise {
    return [
      {
        contentType: "text/markdown",
        data: await base64(this._text),
      },
      ...(await Promise.all(
        this._images.map((image) =>
          base64(image.file).then((data) => ({
            contentType: image.file.type,
            data,
          }))
        )
      )),
    ];
  }
}