import { css, html, LitElement, unsafeCSS } from "lit";
import { property } from "lit/decorators.js";
import Quill from "uxl-quill/dist/quill";
import styles from "./styles.css?inline";
import { template } from "./template";
import { fixSpellCheckerIssue } from "./utils";

fixSpellCheckerIssue(Quill);

export class PrimariaRichTextEditor extends LitElement {
  private textChangeTimeout: number | null = null;

  render() {
    return html` ${template(this)} `;
  }

  static styles = css`
    ${unsafeCSS(styles)}
  `;

  firstUpdated() {
    // const rte: PrimariaRichTextEditor = this;
    this.quill = new Quill(this.shadowRoot?.querySelector("#rte"), this._getOptions());

    this.quill.on("text-change", () => this._debouncedEmitTextChangeEvent());

    this.quill.root.addEventListener("paste", () => {
      this._debouncedEmitTextChangeEvent();
    });
    this.quill.on("selection-change", (range, oldRange, source) => {
      if (range) this.range = range;
    });
  }

  _debouncedEmitTextChangeEvent() {
    if (this.textChangeTimeout) {
      clearTimeout(this.textChangeTimeout);
    }

    this.textChangeTimeout = window.setTimeout(() => {
      this._emitTextChangeEvent();
    }, 200);
  }

  _emitTextChangeEvent() {
    const plainValue = this.quill.getText();
    const values = {
      html: this.shadowRoot?.querySelector(".ql-editor")?.innerHTML,
      plain: plainValue,
    };

    const textChanged = new CustomEvent("text-changed", {
      composed: true,
      detail: values,
    });

    this.dispatchEvent(textChanged);
    this.range = this.getCursorPosition();
  }

  @property()
  quill: Quill | null;

  @property()
  options: string;

  @property({ type: Object })
  range: { index: number; length: number };

  @property({ type: Array })
  availableOptions: string[] = [
    "bold",
    "italic",
    "underline",
    "strike",
    "blockquote",
    "code-block",
    "image",
    "video",
    "link",
    "color",
    "background",
    "ol",
    "ul",
    "subindex",
    "superindex",
    // 'outdent',
    // 'indent',
    "size",
    "header",
    "font",
    "align",
    // "clear",
    "undo",
    "redo",
  ];

  @property({ type: Array })
  availableFormats: string[] = [
    "background",
    "bold",
    "color",
    "font",
    "code",
    "italic",
    "link",
    "size",
    "strike",
    "script",
    "underline",
    "blockquote",
    "header",
    // 'indent',
    "list",
    "align",
    "direction",
    "code-block",
    "formula",
    "image",
    "video",
  ];

  @property()
  formats: string;

  _getOptions() {
    let toolbarOptions = [];
    const availableOpts = this.availableOptions;
    if (this.options === undefined || this.options.length === 0) {
      toolbarOptions = [
        ["bold", "italic", "underline", "strike"],
        ["blockquote", "code-block"],
        [{ header: 1 }, { header: 2 }],
        [{ list: "ordered" }, { list: "bullet" }],
        [{ script: "sub" }, { script: "super" }],
        // [{indent: '-1'}, {indent: '+1'}],
        [{ direction: "rtl" }],
        [{ size: ["small", false, "large", "huge", "20px"] }],
        [{ header: [1, 2, 3, 4, 5, 6, false] }],
        [{ color: [] }, { background: [] }],
        [{ font: [] }],
        [{ align: [] }],
        ["image"],
        ["video"],
        // ["clean"],
      ];
    } else {
      toolbarOptions = this.options.split(",");
      toolbarOptions.forEach((option) => {
        if (availableOpts.indexOf(option) <= -1) toolbarOptions.splice(toolbarOptions.indexOf(option), 1);
      });
      toolbarOptions = toolbarOptions.map(function (option) {
        if (option == "color") return { color: [] };
        else if (option == "ol") return { list: "ordered" };
        else if (option == "ul") return { list: "bullet" };
        else if (option == "subindex") return { script: "sub" };
        else if (option == "superindex") return { script: "super" };
        // else if (option == 'outdent') return {indent: '-1'};
        // else if (option == 'indent') return {indent: '+1'};
        else if (option == "size") return { size: ["small", false, "large", "huge"] };
        else if (option == "header") return { header: [1, 2, 3, 4, 5, 6, false] };
        else if (option == "background") return { background: [] };
        else if (option == "font") return { font: [] };
        else if (option == "align") return { align: [] };
        /*         else if (option == 'undo') return {undo: undo_icon};
        else if (option == 'redo') return {redo: redo_icon}; */ else return option;
      });
      // if (toolbarOptions.indexOf("clean") < 0) {
      // toolbarOptions.push("clean");
      // }
    }

    /* const icons = Quill.import('ui/icons');
    icons['undo'] = undo_icon;
    icons['redo'] = redo_icon; */

    let formats = this.availableFormats;
    if (this.formats) {
      formats = this.formats.split(",");
    }

    return {
      modules: {
        toolbar: {
          container: toolbarOptions,
          handlers: {
            redo() {
              this.quill.history.redo();
            },
            undo() {
              this.quill.history.undo();
            },
          },
        },
        history: {
          delay: 1000,
          maxStack: 50,
          userOnly: false,
        },
        keyboard: {
          bindings: {
            indent: {
              // highlight tab or tab at beginning of list, indent or blockquote
              key: "Tab",
              format: ["blockquote", "indent", "list"],
              handler(range, context) {
                if (
                  (context.collapsed && context.offset !== 0) ||
                  context.format?.list === "ordered" // disable ordered list auto-numbering on indentation
                )
                  return true;
                this.quill.format("indent", "+1", Quill.sources.USER);
                return false;
              },
            },
            "list autofill": {
              key: " ",
              shiftKey: null,
              collapsed: true,
              format: {
                "code-block": false,
                blockquote: false,
                table: false,
              },
              prefix: /^\s*?(\d+\.|-|\*)$/,
              handler(range, context) {
                if (this.quill.scroll.query("list") == null) return true;
                const { length } = context.prefix;
                const line = this.quill.getLine(range.index);
                const offset = line[1];
                if (offset > length) return true;
                this.quill.insertText(range.index, " ", Quill.sources.USER);
                this.quill.setSelection(range.index - length, Quill.sources.SILENT);
                return false;
              },
            },
          },
        },
      },
      theme: "snow",
      formats: formats,
    };
  }

  public getCursorPosition() {
    return this.quill.getSelection();
  }
}
