import { app } from "../../scripts/app.js";
import { $el, ComfyDialog } from "../../scripts/ui.js";
import { customAlert } from "./common.js";

const env = "prod";

let DEFAULT_HOMEPAGE_URL = "https://copus.io";

let API_ENDPOINT = "https://api.client.prod.copus.io";

if (env !== "prod") {
  API_ENDPOINT = "https://api.test.copus.io";
  DEFAULT_HOMEPAGE_URL = "https://test.copus.io";
}

const style = `
  .copus-share-dialog a {
    color: #f8f8f8;
  }
  .copus-share-dialog a:hover {
    color: #007bff;
  }
  .output_label {
    border: 5px solid transparent;
  }
  .output_label:hover {
    border: 5px solid #59E8C6;
  }
  .output_label.checked {
    border: 5px solid #59E8C6;
  }
`;

// Shared component styles
const sectionStyle = {
  marginBottom: 0,
  padding: 0,
  borderRadius: "8px",
  boxShadow: "0 2px 4px rgba(0, 0, 0, 0.05)",
  display: "flex",
  flexDirection: "column",
  justifyContent: "center",
  position: "relative",
};

export class CopusShareDialog extends ComfyDialog {
  static instance = null;

  constructor() {
    super();
    $el("style", {
      textContent: style,
      parent: document.head,
    });
    this.element = $el(
      "div.comfy-modal.copus-share-dialog",
      {
        parent: document.body,
        style: {
          "overflow-y": "auto",
        },
      },
      [$el("div.comfy-modal-content", {}, [...this.createButtons()])]
    );
    this.selectedOutputIndex = 0;
    this.selectedOutput_lock = 0;
    this.selectedNodeId = null;
    this.uploadedImages = [];
    this.allFilesImages = [];
    this.selectedFile = null;
    this.allFiles = [];
    this.titleNum = 0;
  }
  
  createButtons() {
    const inputStyle = {
      display: "block",
      minWidth: "500px",
      width: "100%",
      padding: "10px",
      margin: "10px 0",
      borderRadius: "4px",
      border: "1px solid #ddd",
      boxSizing: "border-box",
    };

    const textAreaStyle = {
      display: "block",
      minWidth: "500px",
      width: "100%",
      padding: "10px",
      margin: "10px 0",
      borderRadius: "4px",
      border: "1px solid #ddd",
      boxSizing: "border-box",
      minHeight: "100px",
      background: "#222",
      resize: "vertical",
      color: "#f2f2f2",
      fontFamily: "Arial",
      fontWeight: "400",
      fontSize: "15px",
    };

    const hyperLinkStyle = {
      display: "block",
      marginBottom: "15px",
      fontWeight: "bold",
      fontSize: "14px",
    };

    const labelStyle = {
      color: "#f8f8f8",
      display: "block",
      margin: "10px 0 0 0",
      fontWeight: "bold",
      textDecoration: "none",
    };

    const buttonStyle = {
      padding: "10px 80px",
      margin: "10px 5px",
      borderRadius: "4px",
      border: "none",
      cursor: "pointer",
      color: "#fff",
      backgroundColor: "#007bff",
    };

    // upload images input
    this.uploadImagesInput = $el("input", {
      type: "file",
      multiple: false,
      style: inputStyle,
      accept: "image/*",
    });

    this.uploadImagesInput.addEventListener("change", async (e) => {
      const file = e.target.files[0];
      if (!file) {
        this.previewImage.src = "";
        this.previewImage.style.display = "none";
        return;
      }
      const reader = new FileReader();
      reader.onload = async (e) => {
        const imgData = e.target.result;
        this.previewImage.src = imgData;
        this.previewImage.style.display = "block";
        this.selectedFile = null;
        // Once user uploads an image, we uncheck all radio buttons
        this.radioButtons.forEach((ele) => {
          ele.checked = false;
          ele.parentElement.classList.remove("checked");
        });

        // Add the opacity style toggle here to indicate that they only need
        // to upload one image or choose one from the outputs.
        this.outputsSection.style.opacity = 0.35;
        this.uploadImagesInput.style.opacity = 1;
      };
      reader.readAsDataURL(file);
    });

    // preview image
    this.previewImage = $el("img", {
      src: "",
      style: {
        width: "100%",
        maxHeight: "100px",
        objectFit: "contain",
        display: "none",
        marginTop: "10px",
      },
    });

    this.keyInput = $el("input", {
      type: "password",
      placeholder: "Copy & paste your API key",
      style: inputStyle,
    });
    this.TitleInput = $el("input", {
      type: "text",
      placeholder: "Title (Required)",
      style: inputStyle,
      maxLength: "70",
      oninput: () => {
        const titleNum = this.TitleInput.value.length;
        titleNumDom.textContent = `${titleNum}/70`;
      },
    });
    this.SubTitleInput = $el("input", {
      type: "text",
      placeholder: "Subtitle (Optional)",
      style: inputStyle,
      maxLength: "350",
      oninput: () => {
        const titleNum = this.SubTitleInput.value.length;
        subTitleNumDom.textContent = `${titleNum}/350`;
      },
    });
    this.LockInput = $el("input", {
      type: "text",
      placeholder: "",
      style:  {
        width: "100px",
        padding: "7px",
        borderRadius: "4px",
        border: "1px solid #ddd",
        boxSizing: "border-box",
      },
      oninput: (event) => {
        let input = event.target.value;
        // Use a regular expression to match a number with up to two decimal places
        const regex = /^\d*\.?\d{0,2}$/;
        if (!regex.test(input)) {
          // If the input doesn't match, remove the last entered character
          event.target.value = input.slice(0, -1);
        }
        const numericValue = parseFloat(input);
        if (numericValue > 9999) {
          input = "9999";
        }
        // Update the input field with the valid value
        event.target.value = input;
      },
    });
    this.descriptionInput = $el("textarea", {
      placeholder: "Content (Optional)",
      style: {
        ...textAreaStyle,
        minHeight: "100px",
      },
    });

    // Header Section
    const headerSection = $el("h3", {
      textContent: "Share your workflow to Copus",
      size: 3,
      color: "white",
      style: {
        "text-align": "center",
        color: "white",
        margin: "0 0 10px 0",
      },
    });
    this.getAPIKeyLink = $el(
      "a",
      {
        style: {
          ...hyperLinkStyle,
          color: "#59E8C6",
        },
        href: `${DEFAULT_HOMEPAGE_URL}?fromPage=comfyUI`,
        target: "_blank",
      },
      ["👉 Get your API key here"]
    );
    const linkSection = $el(
      "div",
      {
        style: {
          marginTop: "10px",
          display: "flex",
          flexDirection: "column",
        },
      },
      [
        // this.communityLink,
        this.getAPIKeyLink,
      ]
    );

    // Account Section
    const accountSection = $el("div", { style: sectionStyle }, [
      $el("label", { style: labelStyle }, ["1️⃣ Copus API Key"]),
      this.keyInput,
    ]);

    // Output Upload Section
    const outputUploadSection = $el("div", { style: sectionStyle }, [
      $el(
        "label",
        {
          style: {
            ...labelStyle,
            margin: "10px 0 0 0",
          },
        },
        ["2️⃣ Image/Thumbnail (Required)"]
      ),
      this.previewImage,
      this.uploadImagesInput,
    ]);

    // Outputs Section
    this.outputsSection = $el(
      "div",
      {
        id: "selectOutputs",
      },
      []
    );
    
    const titleNumDom = $el(
      "label",
      {
        style: {
          fontSize: "12px",
          position: "absolute",
          right: "10px",
          bottom: "-10px",
          color: "#999",
        },
      },
      ["0/70"]
    );
    const subTitleNumDom = $el(
      "label",
      {
        style: {
          fontSize: "12px",
          position: "absolute",
          right: "10px",
          bottom: "-10px",
          color: "#999",
        },
      },
      ["0/350"]
    );
    const descriptionNumDom = $el(
      "label",
      {
        style: {
          fontSize: "12px",
          position: "absolute",
          right: "10px",
          bottom: "-10px",
          color: "#999",
        },
      },
      ["0/70"]
    );
    // Additional Inputs Section
    const additionalInputsSection = $el(
      "div",
      { style: { ...sectionStyle,  } },
      [
        $el("label", { style: labelStyle }, ["3️⃣ Title "]),
        this.TitleInput,
        titleNumDom,
      ]
    );
    const SubtitleSection = $el("div", { style: sectionStyle }, [
      $el("label", { style: labelStyle }, ["4️⃣ Subtitle "]),
      this.SubTitleInput,
      subTitleNumDom,
    ]);
    const DescriptionSection = $el("div", { style: sectionStyle }, [
      $el("label", { style: labelStyle }, ["5️⃣ Description "]),
      this.descriptionInput,
      // descriptionNumDom,
    ]);
    // switch  between outputs section and additional inputs section
    this.radioButtons_lock = [];

    this.radioButtonsCheck_lock = $el("input", {
      type: "radio",
      name: "output_type_lock",
      value: "0",
      id: "blockchain1_lock",
      checked: true,
    });
    this.radioButtonsCheckOff_lock = $el("input", {
      type: "radio",
      name: "output_type_lock",
      value: "1",
      id: "blockchain_lock",
    });

    const blockChainSection_lock = $el("div", { style: sectionStyle }, [
      $el("label", { style: labelStyle }, ["6️⃣ Pay to download"]),
      $el(
        "label",
        {
          style: {
            marginTop: "10px",
            display: "flex",
            alignItems: "center",
            cursor: "pointer",
          },
        },
        [
          this.radioButtonsCheck_lock,
          $el("div", { style: { marginLeft: "5px" ,display:'flex',alignItems:'center'} }, [
            $el("span", { style: { marginLeft: "5px" } }, ["ON"]),
            $el("span", { style: { marginLeft: "20px",marginRight:'10px' ,color:'#fff'} }, ["Price US$"]),
            this.LockInput
          ]),
        ]
      ),
      $el(
        "label",
        { style: { display: "flex", alignItems: "center", cursor: "pointer" } },
        [
          this.radioButtonsCheckOff_lock,
          $el("span", { style: { marginLeft: "5px" } }, ["OFF"]),
        ]
      ),
      
      $el(
        "p",
        { style: { fontSize: "16px", color: "#fff", margin: "10px 0 0 0" } },
        ["Get paid from your workflow. You can change the price and withdraw your earnings on Copus."]
      ),
    ]);

    this.radioButtons = [];

    this.radioButtonsCheck = $el("input", {
      type: "radio",
      name: "output_type",
      value: "0",
      id: "blockchain1",
      checked: true,
    });
    this.radioButtonsCheckOff = $el("input", {
      type: "radio",
      name: "output_type",
      value: "1",
      id: "blockchain",
    });

    const blockChainSection = $el("div", { style: sectionStyle }, [
      $el("label", { style: labelStyle }, ["7️⃣ Store on blockchain "]),
      $el(
        "label",
        {
          style: {
            marginTop: "10px",
            display: "flex",
            alignItems: "center",
            cursor: "pointer",
          },
        },
        [
          this.radioButtonsCheck,
          $el("span", { style: { marginLeft: "5px" } }, ["ON"]),
        ]
      ),
      $el(
        "label",
        { style: { display: "flex", alignItems: "center", cursor: "pointer" } },
        [
          this.radioButtonsCheckOff,
          $el("span", { style: { marginLeft: "5px" } }, ["OFF"]),
        ]
      ),
      $el(
        "p",
        { style: { fontSize: "16px", color: "#fff", margin: "10px 0 0 0" } },
        ["Secure ownership with a permanent & decentralized storage"]
      ),
    ]);


    // Message Section
    this.message = $el(
      "div",
      {
        style: {
          color: "#ff3d00",
          textAlign: "center",
          padding: "10px",
          fontSize: "20px",
        },
      },
      []
    );

    this.shareButton = $el("button", {
      type: "submit",
      textContent: "Share",
      style: buttonStyle,
      onclick: () => {
        this.handleShareButtonClick();
      },
    });

    // Share and Close Buttons
    const buttonsSection = $el(
      "div",
      {
        style: {
          textAlign: "right",
          marginTop: "20px",
          display: "flex",
          justifyContent: "space-between",
        },
      },
      [
        $el("button", {
          type: "button",
          textContent: "Close",
          style: {
            ...buttonStyle,
            backgroundColor: undefined,
          },
          onclick: () => {
            this.close();
          },
        }),
        this.shareButton,
      ]
    );

    // Composing the full layout
    const layout = [
      headerSection,
      linkSection,
      accountSection,
      outputUploadSection,
      this.outputsSection,
      additionalInputsSection,
      SubtitleSection,
      DescriptionSection,
      // contestSection,
      blockChainSection_lock,
      blockChainSection,
      this.message,
      buttonsSection,
    ];

    return layout;
  }
  /**
   * api 
   * @param {url} path
   * @param {params} options
   * @param {statusText} statusText
   * @returns
   */
  async fetchApi(path, options, statusText) {
    if (statusText) {
      this.message.textContent = statusText;
    }
    const fullPath = new URL(API_ENDPOINT + path);
    const response = await fetch(fullPath, options);
    if (!response.ok) {
      throw new Error(response.statusText);
    }
    if (statusText) {
      this.message.textContent = "";
    }
    const data = await response.json();
    return {
      ok: response.ok,
      statusText: response.statusText,
      status: response.status,
      data,
    };
  }
  /**
   * @param {file} uploadFile
   */
  async uploadThumbnail(uploadFile, type) {
    const form = new FormData();
    form.append("file", uploadFile);
    form.append("apiToken", this.keyInput.value);
    try {
      const res = await this.fetchApi(
        `/client/common/opus/uploadImage`,
        {
          method: "POST",
          body: form,
        },
        "Uploading thumbnail..."
      );
      if (res.status && res.data.status && res.data) {
        const { data } = res.data;
        if (type) {
          this.allFilesImages.push({
            url: data,
          });
        }
        this.uploadedImages.push({
          url: data,
        });
      } else {
        throw new Error("make sure your API key is correct and try again later");
      }
    } catch (e) {
      if (e?.response?.status === 413) {
        throw new Error("File size is too large (max 20MB)");
      } else {
        throw new Error("Error uploading thumbnail: " + e.message);
      }
    }
  }

  async handleShareButtonClick() {
    this.message.textContent = "";
    try {
      this.shareButton.disabled = true;
      this.shareButton.textContent = "Sharing...";
      await this.share();
    } catch (e) {
      customAlert(e.message);
    }
    this.shareButton.disabled = false;
    this.shareButton.textContent = "Share";
  }
  /**
   * share
   * @param {string} title
   * @param {string} subtitle
   * @param {string} content
   * @param {boolean} storeOnChain
   * @param {string} coverUrl
   * @param {string[]} imageUrls
   * @param {string} apiToken
   */
  async share() {
    const prompt = await app.graphToPrompt();
    const workflowJSON = prompt["workflow"];
    const form_values = {
      title: this.TitleInput.value,
      subTitle: this.SubTitleInput.value,
      content: this.descriptionInput.value,
      storeOnChain: this.radioButtonsCheck.checked ? true : false,
      lockState:this.radioButtonsCheck_lock.checked ? 2 : 0,
      unlockPrice:this.LockInput.value,
    };

    if (!this.keyInput.value) {
      throw new Error("API key is required");
    }

    if (!this.uploadImagesInput.files[0] && !this.selectedFile) {
      throw new Error("Thumbnail is required");
    }

    if (!form_values.title) {
      throw new Error("Title is required");
    }

    if(this.radioButtonsCheck_lock.checked){
      if (!this.LockInput.value){
        throw new Error("Price is required");
      }
    }

    if (!this.uploadedImages.length) {
      if (this.selectedFile) {
        await this.uploadThumbnail(this.selectedFile);
      } else {
        for (const file of this.uploadImagesInput.files) {
          try {
            await this.uploadThumbnail(file);
          } catch (e) {
            this.uploadedImages = [];
            throw new Error(e.message);
          }
        }

        if (this.uploadImagesInput.files.length === 0) {
          throw new Error("No thumbnail uploaded");
        }
      }
    }
    if (this.allFiles.length > 0) {
      for (const file of this.allFiles) {
        try {
          await this.uploadThumbnail(file, true);
        } catch (e) {
          this.allFilesImages = [];
          throw new Error(e.message);
        }
      }
    }
    try {
      const res = await this.fetchApi(
        "/client/common/opus/shareFromComfyUI",
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            workflowJson: workflowJSON,
            apiToken: this.keyInput.value,
            coverUrl: this.uploadedImages[0].url,
            imageUrls: this.allFilesImages.map((image) => image.url),
            ...form_values,
          }),
        },
        "Uploading workflow..."
      );

     if (res.status && res.data.status && res.data) {
      localStorage.setItem("copus_token",this.keyInput.value);
       const { data } = res.data;
       if (data) {
         const url = `${DEFAULT_HOMEPAGE_URL}/work/${data}`;
         this.message.innerHTML = `Workflow has been shared successfully. <a href="${url}" target="_blank">Click here to view it.</a>`;
         this.previewImage.src = "";
         this.previewImage.style.display = "none";
         this.uploadedImages = [];
         this.allFilesImages = [];
         this.allFiles = [];
         this.TitleInput.value = "";
         this.SubTitleInput.value = "";
         this.descriptionInput.value = "";
         this.selectedFile = null;
       }
     }
    } catch (e) {
      throw new Error("Error sharing workflow: " + e.message);
    }
  }

  async fetchImageBlob(url) {
    const response = await fetch(url);
    const blob = await response.blob();
    return blob;
  }

  async show({ potential_outputs, potential_output_nodes } = {}) {
    // Sort `potential_output_nodes` by node ID to make the order always
    // consistent, but we should also keep `potential_outputs` in the same
    // order as `potential_output_nodes`.
    const potential_output_to_order = {};
    potential_output_nodes.forEach((node, index) => {
      if (node.id in potential_output_to_order) {
        potential_output_to_order[node.id][1].push(potential_outputs[index]);
      } else {
        potential_output_to_order[node.id] = [node, [potential_outputs[index]]];
      }
    });
    // Sort the object `potential_output_to_order` by key (node ID)
    const sorted_potential_output_to_order = Object.fromEntries(
      Object.entries(potential_output_to_order).sort(
        (a, b) => a[0].id - b[0].id
      )
    );
    const sorted_potential_outputs = [];
    const sorted_potential_output_nodes = [];
    for (const [key, value] of Object.entries(
      sorted_potential_output_to_order
    )) {
      sorted_potential_output_nodes.push(value[0]);
      sorted_potential_outputs.push(...value[1]);
    }
    potential_output_nodes = sorted_potential_output_nodes;
    potential_outputs = sorted_potential_outputs;
    const apiToken = localStorage.getItem("copus_token");
    this.message.innerHTML = "";
    this.message.textContent = "";
    this.element.style.display = "block";
    this.previewImage.src = "";
    this.previewImage.style.display = "none";
    this.keyInput.value = apiToken!=null?apiToken:"";
    this.uploadedImages = [];
    this.allFilesImages = [];
    this.allFiles = [];
    // If `selectedNodeId` is provided, we will select the corresponding radio
    // button for the node. In addition, we move the selected radio button to
    // the top of the list.
    if (this.selectedNodeId) {
      const index = potential_output_nodes.findIndex(
        (node) => node.id === this.selectedNodeId
      );
      if (index >= 0) {
        this.selectedOutputIndex = index;
      }
    }

    this.radioButtons = [];
    const new_radio_buttons = $el(
      "div",
      {
        id: "selectOutput-Options",
        style: {
          "overflow-y": "scroll",
          "max-height": "200px",
          display: "grid",
          "grid-template-columns": "repeat(auto-fit, minmax(100px, 1fr))",
          "grid-template-rows": "auto",
          "grid-column-gap": "10px",
          "grid-row-gap": "10px",
          "margin-bottom": "10px",
          padding: "10px",
          "border-radius": "8px",
          "box-shadow": "0 2px 4px rgba(0, 0, 0, 0.05)",
          "background-color": "var(--bg-color)",
        },
      },
      potential_outputs.map((output, index) => {
        const { node_id } = output;
        const radio_button = $el(
          "input",
          {
            type: "radio",
            name: "selectOutputImages",
            value: index,
            required: index === 0,
          },
          []
        );
        let radio_button_img;
        let filename;
        if (output.type === "image" || output.type === "temp") {
          radio_button_img = $el(
            "img",
            {
              src: `/view?filename=${output.image.filename}&subfolder=${output.image.subfolder}&type=${output.image.type}`,
              style: {
                width: "100px",
                height: "100px",
                objectFit: "cover",
                borderRadius: "5px",
              },
            },
            []
          );
          filename = output.image.filename;
        } else if (output.type === "output") {
          radio_button_img = $el(
            "img",
            {
              src: output.output.value,
              style: {
                width: "auto",
                height: "100px",
                objectFit: "cover",
                borderRadius: "5px",
              },
            },
            []
          );
          filename = output.filename;
        } else {
          // unsupported output type
          // this should never happen
          radio_button_img = $el(
            "img",
            {
              src: "",
              style: { width: "auto", height: "100px" },
            },
            []
          );
        }
        const radio_button_text = $el(
          "span",
          {
            style: {
              color: "gray",
              display: "block",
              fontSize: "12px",
              overflowX: "hidden",
              textOverflow: "ellipsis",
              textWrap: "nowrap",
              maxWidth: "100px",
            },
          },
          [output.title]
        );
        const node_id_chip = $el(
          "span",
          {
            style: {
              color: "#FBFBFD",
              display: "block",
              backgroundColor: "rgba(0, 0, 0, 0.5)",
              fontSize: "12px",
              overflowX: "hidden",
              padding: "2px 3px",
              textOverflow: "ellipsis",
              textWrap: "nowrap",
              maxWidth: "100px",
              position: "absolute",
              top: "3px",
              left: "3px",
              borderRadius: "3px",
            },
          },
          [`Node: ${node_id}`]
        );
        radio_button.style.color = "var(--fg-color)";
        radio_button.checked = this.selectedOutputIndex === index;

        radio_button.onchange = async () => {
          this.selectedOutputIndex = parseInt(radio_button.value);

          // Remove the "checked" class from all radio buttons
          this.radioButtons.forEach((ele) => {
            ele.parentElement.classList.remove("checked");
          });
          radio_button.parentElement.classList.add("checked");

          this.fetchImageBlob(radio_button_img.src).then((blob) => {
            const file = new File([blob], filename, {
              type: blob.type,
            });
            this.previewImage.src = radio_button_img.src;
            this.previewImage.style.display = "block";
            this.selectedFile = file;
          });

          // Add the opacity style toggle here to indicate that they only need
          // to upload one image or choose one from the outputs.
          this.outputsSection.style.opacity = 1;
          this.uploadImagesInput.style.opacity = 0.35;
        };

        if (radio_button.checked) {
          this.fetchImageBlob(radio_button_img.src).then((blob) => {
            const file = new File([blob], filename, {
              type: blob.type,
            });
            this.previewImage.src = radio_button_img.src;
            this.previewImage.style.display = "block";
            this.selectedFile = file;
          });
          // Add the opacity style toggle here to indicate that they only need
          // to upload one image or choose one from the outputs.
          this.outputsSection.style.opacity = 1;
          this.uploadImagesInput.style.opacity = 0.35;
        }
        this.radioButtons.push(radio_button);
        let src = "";
        if (output.type === "image" || output.type === "temp") {
          filename = output.image.filename;
          src = `/view?filename=${output.image.filename}&subfolder=${output.image.subfolder}&type=${output.image.type}`;
        } else if (output.type === "output") {
          src = output.output.value;
          filename = output.filename;
        }
        if (src) {
          this.fetchImageBlob(src).then((blob) => {
            const file = new File([blob], filename, {
              type: blob.type,
            });
            this.allFiles.push(file);
          });
        }
        return $el(
          `label.output_label${radio_button.checked ? ".checked" : ""}`,
          {
            style: {
              display: "flex",
              flexDirection: "column",
              alignItems: "center",
              justifyContent: "center",
              marginBottom: "10px",
              cursor: "pointer",
              position: "relative",
            },
          },
          [radio_button_img, radio_button_text, radio_button, node_id_chip]
        );
      })
    );

    const header = $el(
      "p",
      {
        textContent:
          this.radioButtons.length === 0
            ? "Queue Prompt to see the outputs"
            : "Or choose one from the outputs (scroll to see all)",
        size: 2,
        color: "white",
        style: {
          color: "white",
          margin: "0 0 5px 0",
          fontSize: "12px",
        },
      },
      []
    );
    this.outputsSection.innerHTML = "";
    this.outputsSection.appendChild(header);
    this.outputsSection.appendChild(new_radio_buttons);
  }
}