import { IValueLabel } from "../schema";
import { Api } from "./Api";
import { Utils } from "./Utils";

export class Editor {
    editorElement: HTMLElement;
    private wrapper: HTMLElement;
    private parent: HTMLElement;
    private value: string;
    private label: string;
    private defaultFontSize: string = "14px"; // Default font size
  
    constructor(parent: HTMLElement, value = "", label = "Content") {
      this.parent = parent;
      this.value = value;
      this.label = label;
      this.editorElement = document.createElement("div");
      this.wrapper = document.createElement("div");
      parent.appendChild(Utils.createLabel(this.label));
      this.setupButtons();
      this.configure();
    }
  
    configure() {
      this.editorElement.contentEditable = "true";
      this.editorElement.style.borderRadius = "4px";
      this.editorElement.style.minHeight = "200px";
      this.editorElement.style.position = "relative";
      this.editorElement.style.padding = "20px";
      this.editorElement.style.fontSize = this.defaultFontSize; // Apply default font size
      this.editorElement.innerHTML = this.value;
  
      // wrapper
      this.wrapper.classList.add("editor-wrapper", "form-control", "mb-3");
      this.wrapper.style.padding = "0";
      this.wrapper.appendChild(this.editorElement);
      this.parent.appendChild(this.wrapper);
    }
  
    private setupButtons() {
      const container = document.createElement("div");
      container.style.borderBottom = "1px solid #dee2e6";
      container.style.boxShadow = "0 3px 5px 0 #d4d4d469";
      container.classList.add(
        "editor-buttons",
        "d-flex",
        "gap-2",
        "p-2",
        "align-items-center"
      );
  
      const boldButton = this.createButton(
        "<i class='bi bi-type-bold'></i>",
        () => this.makeBold()
      );
      const italicButton = this.createButton(
        "<i class='bi bi-type-italic'></i>",
        () => this.makeItalic()
      );
      const ulBtn = this.createButton("<i class='bi bi-list-ul'></i>", () =>
        this.makeList()
      );
      const olBtn = this.createButton("<i class='bi bi-list-ol'></i>", () =>
        this.makeOrderedList()
      );
      const underlineBtn = this.createButton(
        "<i class='bi bi-type-underline'></i>",
        () => this.makeUnderline()
      );
      const strikeBtn = this.createButton(
        "<i class='bi bi-type-strikethrough'></i>",
        () => this.makeStrike()
      );
  
      const imageButton = this.createButton("<i class='bi bi-image'></i>", () =>
        this.insertImage()
      );
      const tableButton = this.createButton(
        "<i class='bi bi-table'></i>",
        () => this.insertTable(3, 3) // Example: Insert a 3x3 table
      );
      container.appendChild(tableButton);
      const fontDropdown = this.createFontDropdown();
      const colorPicker = this.createColorPicker();
      const fontSizeDropDown = this.createFontSizeDropDown();
  
      [
        boldButton,
        italicButton,
        ulBtn,
        olBtn,
        underlineBtn,
        strikeBtn,
        imageButton,
        tableButton,
        fontDropdown,
        colorPicker,
        fontSizeDropDown,
      ].forEach((element) => {
        container.appendChild(element);
      });
  
      this.wrapper.appendChild(container);
    }
    private insertTable(rows: number, cols: number) {
      const table = document.createElement("table");
      table.classList.add("table", "table-bordered", "table-striped","w-fit");
      table.classList.add("table");
      const tbody = document.createElement("tbody");
  
      // Create table rows and cells
      for (let i = 0; i < rows; i++) {
        const tr = document.createElement("tr");
        for (let j = 0; j < cols; j++) {
          const td = document.createElement("td");
          td.contentEditable = "true"; // Make cells editable
          td.style.padding = "8px";
          td.innerHTML = `Enter text here...`;
          tr.appendChild(td);
        }
        tbody.appendChild(tr);
      }
  
      table.appendChild(tbody);
      const range = window.getSelection()?.getRangeAt(0);
      range?.insertNode(table);
    }
    private insertImage() {
      const imgSrc = "https://placehold.co/600x400";
      const imgElement = document.createElement("img");
      imgElement.src = imgSrc;
      imgElement.id = this.getId("img");
      imgElement.style.width = "450px";
      const range = window.getSelection()?.getRangeAt(0);
      range?.insertNode(imgElement);
      imgElement.scrollIntoView({ behavior: "smooth", block: "center" });
      imgElement.onclick = () => {
        this.showImageModal(imgElement);
      };
    }
    showImageModal(imgElement: HTMLImageElement) {
      const div = document.createElement("div");
      div.classList.add("my-modal");
      const input = document.createElement("input");
      input.type = "file";
      input.accept = "image/*";
      input.onchange = (e) => {
        const file = (e.target as HTMLInputElement).files?.[0];
        if (file) {
          const reader = new FileReader();
          reader.onload = (e) => {
            const api = new Api();
            api.uploadBase64Image(
              [e.target?.result as string],
              (data: string[]) => {
                console.log("Image uploaded", data);
                if (data && data.length > 0) {
                  imgElement.src = data[0];
                  div.remove();
                }
              }
            );
          };
          reader.readAsDataURL(file);
        }
      };
      div.appendChild(input);
      this.editorElement.appendChild(div);
    }
    getId(prefix: string): string {
      return `${prefix}-${Math.random().toString(36).substr(2, 9)}`;
    }
    private createButton(
      htmlContent: string,
      onClick: () => void
    ): HTMLButtonElement {
      const button = document.createElement("button");
      button.innerHTML = htmlContent;
      button.classList.add("btn", "btn-light", "m-0", "btn-sm");
      button.style.width = "fit-content";
      button.addEventListener("click", onClick);
      return button;
    }
  
    private createFontDropdown(): HTMLSelectElement {
      const select = document.createElement("select");
      select.classList.add("form-select", "btn-sm", "me-2", "p-1");
      select.style.maxWidth = "130px";
      const options = [
        { value: "p", label: "Paragraph" },
        { value: "h1", label: "Heading 1" },
        { value: "h2", label: "Heading 2" },
        { value: "h3", label: "Heading 3" },
        { value: "h4", label: "Heading 4" },
        { value: "h5", label: "Heading 5" },
        { value: "h6", label: "Heading 6" },
      ];
  
      options.forEach((option) => {
        const optionElement = document.createElement("option");
        optionElement.innerHTML = option.label;
        optionElement.value = option.value;
        select.appendChild(optionElement);
      });
  
      select.addEventListener("change", () => this.applyTag(select.value));
      return select;
    }
  
    private createColorPicker(): HTMLInputElement {
      const colorPicker = document.createElement("input");
      colorPicker.type = "color";
      colorPicker.style.width = "49px";
      colorPicker.style.padding = "6px";
      colorPicker.style.background = "#002b51";
      colorPicker.classList.add("form-control", "btn-sm", "me-2", "p-0");
      colorPicker.addEventListener("input", () =>
        this.changeTextColor(colorPicker.value)
      );
      return colorPicker;
    }
  
    private createFontSizeDropDown(): HTMLSelectElement {
      const select = document.createElement("select");
      select.classList.add("form-select", "btn-sm", "me-2", "p-1");
      select.style.maxWidth = "130px";
      const options: IValueLabel[] = [];
      for (let i = 1; i <= 200; i++) {
        options.push({ value: `${i}px`, label: `${i} pixels` });
      }
  
      options.forEach((option) => {
        const optionElement = document.createElement("option");
        optionElement.innerHTML = option.label;
        optionElement.value = option.value;
        select.appendChild(optionElement);
      });
      select.value = this.defaultFontSize; // Set default font size in the dropdown
      select.addEventListener("change", () => this.changeFontSize(select.value));
      return select;
    }
  
    private applyTag(tag: string) {
      document.execCommand("formatBlock", false, tag);
    }
  
    private makeBold() {
      document.execCommand("bold");
    }
  
    private makeItalic() {
      document.execCommand("italic");
    }
  
    private makeList() {
      document.execCommand("insertUnorderedList");
    }
  
    private makeOrderedList() {
      document.execCommand("insertOrderedList");
    }
  
    private makeUnderline() {
      document.execCommand("underline");
    }
  
    private makeStrike() {
      document.execCommand("strikeThrough");
    }
  
    private changeTextColor(color: string) {
      document.execCommand("foreColor", false, color);
    }
  
    private changeFontSize(fontSize: string) {
      const selection = window.getSelection();
      if (selection && selection.rangeCount > 0) {
        const range = selection.getRangeAt(0);
        let parentElement = range.commonAncestorContainer as HTMLElement;
  
        // Check if the common ancestor is a text node, then get its parent node
        if (parentElement.nodeType === Node.TEXT_NODE) {
          parentElement = parentElement.parentNode as HTMLElement;
        }
  
        // Check if the parent element is a <span> with font size style
        if (parentElement.tagName === "SPAN" && parentElement.style.fontSize) {
          parentElement.style.fontSize = fontSize;
        } else {
          const span = document.createElement("span");
          span.style.fontSize = fontSize;
          range.surroundContents(span);
        }
      }
    }
  }