import { app } from '../../../scripts/app.js'
import { api } from '../../../scripts/api.js'
import { ComfyWidgets } from '../../../scripts/widgets.js'
import { $el } from '../../../scripts/ui.js'

import { loadCSS, injectCSS } from './common.js'

import PhotoSwipeLightbox from '/mixlab/app/lib/photoswipe-lightbox.esm.min.js'

loadCSS('/mixlab/app/lib/photoswipe.min.css')
injectCSS(`.pswp__custom-caption {
      background: rgb(20 27 70);
      font-size: 16px;
      color: #fff;
      width: calc(100% - 32px);
      max-width: 980px;
      padding: 2px 8px;
      border-radius: 4px;
      position: absolute;
      left: 50%;
      bottom: 16px;
      transform: translateX(-50%);
    }
    .pswp__custom-caption a {
      color: #fff;
      text-decoration: underline;
    }
    .hidden-caption-content {
      display: none;
    }`)

function initLightBox () {
  const lightbox = new PhotoSwipeLightbox({
    gallery: '.prompt_image_output',
    children: 'a',
    pswpModule: () => import('/mixlab/app/lib/photoswipe.esm.min.js')
  })

  lightbox.on('uiRegister', function () {
    lightbox.pswp.ui.registerElement({
      name: 'custom-caption',
      order: 9,
      isButton: false,
      appendTo: 'root',
      html: 'Caption text',
      onInit: (el, pswp) => {
        lightbox.pswp.on('change', () => {
          const currSlideElement = lightbox.pswp.currSlide.data.element
          let captionHTML = ''
          if (currSlideElement) {
            const hiddenCaption = currSlideElement.querySelector(
              '.hidden-caption-content'
            )
            if (hiddenCaption) {
              // get caption from element with class hidden-caption-content
              captionHTML = hiddenCaption.innerHTML
            } else {
              // get caption from alt attribute
              captionHTML = currSlideElement
                .querySelector('img')
                .getAttribute('alt')
            }
          }
          el.innerHTML = captionHTML || ''
        })
      }
    })
  })

  lightbox.init()
}

function get_position_style (ctx, widget_width, y, node_height) {
  const MARGIN = 4 // the margin around the html element

  /* Create a transform that deals with all the scrolling and zooming */
  const elRect = ctx.canvas.getBoundingClientRect()
  const transform = new DOMMatrix()
    .scaleSelf(
      elRect.width / ctx.canvas.width,
      elRect.height / ctx.canvas.height
    )
    .multiplySelf(ctx.getTransform())
    .translateSelf(MARGIN, MARGIN + y)

  return {
    transformOrigin: '0 0',
    transform: transform,
    left:
      document.querySelector('.comfy-menu').style.display === 'none'
        ? `60px`
        : `0`,
    top: `0`,
    cursor: 'pointer',
    position: 'absolute',
    maxWidth: `${widget_width - MARGIN * 2}px`,
    // maxHeight: `${node_height - MARGIN * 2}px`, // we're assuming we have the whole height of the node
    width: `${widget_width - MARGIN * 2 - 24}px`,
    // height: `${node_height * 0.3 - MARGIN * 2}px`,
    // background: '#EEEEEE',
    paddingLeft: '12px',
    display: 'flex',
    flexDirection: 'row',
    // alignItems: 'center',
    justifyContent: 'space-between'
  }
}
function createImage (url) {
  let im = new Image()
  return new Promise((res, rej) => {
    im.onload = () => res(im)
    im.src = url
  })
}

async function fetchImage (url) {
  try {
    const response = await fetch(url)
    const blob = await response.blob()

    return blob
  } catch (error) {
    console.error('出现错误:', error)
  }
}

const getLocalData = key => {
  let data = {}
  try {
    data = JSON.parse(localStorage.getItem(key)) || {}
  } catch (error) {
    return {}
  }
  return data
}

const setLocalDataOfWin = (key, value) => {
  localStorage.setItem(key, JSON.stringify(value))
  // window[key] = value
}

const createSelect = (select, opts, targetWidget) => {
  select.style.display = 'block'
  let html = ''
  let isMatch = false
  for (const opt of opts) {
    html += `<option value='${opt}' ${
      targetWidget.value === opt ? 'selected' : ''
    }>${opt}</option>`
    if (targetWidget.value === opt) isMatch = true
  }
  select.innerHTML = html
  if (!isMatch) targetWidget.value = opts[0]
  // 添加change事件监听器
  select.addEventListener('change', function () {
    // 获取选中的选项的值
    var selectedOption = select.options[select.selectedIndex].value
    targetWidget.value = selectedOption
    // console.log(widget,selectedOption)
  })
}

app.registerExtension({
  name: 'Mixlab.prompt.RandomPrompt',
  async beforeRegisterNodeDef (nodeType, nodeData, app) {
    if (nodeType.comfyClass == 'RandomPrompt') {
      const orig_nodeCreated = nodeType.prototype.onNodeCreated
      nodeType.prototype.onNodeCreated = async function () {
        orig_nodeCreated?.apply(this, arguments)

        const mutable_prompt = this.widgets.filter(
          w => w.name == 'mutable_prompt'
        )[0]
        // console.log('PromptSlide nodeData', prompt_keyword)

        const widget = {
          type: 'div',
          name: 'upload',
          draw (ctx, node, widget_width, y, widget_height) {
            Object.assign(
              this.div.style,
              get_position_style(
                ctx,
                widget_width,
                y + widget_height + 24,
                node.size[1]
              )
            )
          }
        }

        widget.div = $el('div', {})

        const btn = document.createElement('button')
        btn.innerText = 'Upload Keywords'

        btn.style = `cursor: pointer;
        font-weight: 300;
        margin: 2px; 
        color: var(--descrip-text);
        background-color: var(--comfy-input-bg);
        border-radius: 8px;
        border-color: var(--border-color);
        border-style: solid;height: 30px;min-width: 122px;
       `

        // const btn=document.createElement('button');
        // btn.innerText='Upload'
        btn.addEventListener('click', () => {
          let inp = document.createElement('input')
          inp.type = 'file'
          inp.accept = '.txt'
          inp.click()
          inp.addEventListener('change', event => {
            // 获取选择的文件
            const file = event.target.files[0]
            this.title = file.name.split('.')[0]

            // console.log(file.name.split('.')[0])
            // 创建文件读取器
            const reader = new FileReader()

            // 定义读取完成事件的回调函数
            reader.onload = event => {
              // 读取完成后的文本内容
              const fileContent = event.target.result.split('\n')
              const keywords = Array.from(fileContent, f => f.trim()).filter(
                f => f
              )
              // 打印文件内容
              //   console.log(keywords)

              mutable_prompt.value = keywords.join('\n')

              inp.remove()
            }

            // 以文本方式读取文件
            reader.readAsText(file)
          })
        })

        widget.div.appendChild(btn)
        document.body.appendChild(widget.div)
        this.addCustomWidget(widget)

        const onRemoved = this.onRemoved
        this.onRemoved = () => {
          widget.div.remove()
          return onRemoved?.()
        }

        if (this.onResize) {
          this.onResize(this.size)
        }

        this.serialize_widgets = true //需要保存参数
      }
    }
  },
  async loadedGraphNode (node, app) {
    if (node.type === 'RandomPrompt') {
    }
  }
})

app.registerExtension({
  name: 'Mixlab.prompt.PromptSlide',
  async beforeRegisterNodeDef (nodeType, nodeData, app) {
    if (nodeType.comfyClass == 'PromptSlide') {
      const orig_nodeCreated = nodeType.prototype.onNodeCreated
      nodeType.prototype.onNodeCreated = async function () {
        orig_nodeCreated?.apply(this, arguments)

        const prompt_keyword = this.widgets.filter(
          w => w.name == 'prompt_keyword'
        )[0]
        // console.log('PromptSlide nodeData', prompt_keyword)

        const widget = {
          type: 'div',
          name: 'upload',
          draw (ctx, node, widget_width, y, widget_height) {
            Object.assign(
              this.div.style,
              get_position_style(ctx, widget_width, y, node.size[1])
            )
          }
        }

        widget.div = $el('div', {})

        const btn = document.createElement('button')
        btn.innerText = 'Upload Keywords'

        btn.style = `cursor: pointer;
        font-weight: 300;
        margin: 2px; 
        color: var(--descrip-text);
        background-color: var(--comfy-input-bg);
        border-radius: 8px;
        border-color: var(--border-color);
        border-style: solid;    height: 30px;min-width: 122px;
       `

        const select = document.createElement('select')
        select.style = `display:none;cursor: pointer;
        font-weight: 300;
        margin: 2px; 
        color: var(--descrip-text);
        background-color: var(--comfy-input-bg);
        border-radius: 8px;
        border-color: var(--border-color);
        border-style: solid;    height: 30px;min-width: 100px;
       `
        widget.select = select

        // const btn=document.createElement('button');
        // btn.innerText='Upload'
        btn.addEventListener('click', () => {
          let inp = document.createElement('input')
          inp.type = 'file'
          inp.accept = '.txt'
          inp.click()
          inp.addEventListener('change', event => {
            // 获取选择的文件
            const file = event.target.files[0]
            this.title = file.name.split('.')[0]

            // console.log(file.name.split('.')[0])
            // 创建文件读取器
            const reader = new FileReader()

            // 定义读取完成事件的回调函数
            reader.onload = event => {
              // 读取完成后的文本内容
              const fileContent = event.target.result.split('\n')
              const keywords = Array.from(fileContent, f => f.trim()).filter(
                f => f
              )
              // 打印文件内容
              //   console.log(keywords)

              widget.value = JSON.stringify(keywords)

              // let ks = getLocalData(`_mixlab_PromptSlide`)
              // ks[this.id] = keywords
              // setLocalDataOfWin(`_mixlab_PromptSlide`, ks)

              createSelect(select, keywords, prompt_keyword)

              inp.remove()
            }

            // 以文本方式读取文件
            reader.readAsText(file)
          })
        })

        widget.div.appendChild(btn)
        widget.div.appendChild(select)
        document.body.appendChild(widget.div)
        this.addCustomWidget(widget)

        const onRemoved = this.onRemoved
        this.onRemoved = () => {
          widget.div.remove()
          return onRemoved?.()
        }

        if (this.onResize) {
          this.onResize(this.size)
        }

        this.serialize_widgets = true //需要保存参数
      }
    }
  },
  async loadedGraphNode (node, app) {
    if (node.type === 'PromptSlide') {
      try {
        let prompt = node.widgets.filter(w => w.name === 'prompt_keyword')[0]
        // let ks = getLocalData(`_mixlab_PromptSlide`)
        let uploadWidget = node.widgets.filter(w => w.name == 'upload')[0]
        // console.log('##widget', uploadWidget.value)
        let keywords = JSON.parse(uploadWidget.value)
        // console.log('keywords',keywords)
        let widget = node.widgets.filter(w => w.select)[0]
        if (keywords && keywords[0]) {
          widget.select.style.display = 'block'
          createSelect(widget.select, keywords, prompt)
        }
      } catch (error) {}
    }
  }
})

const _createResult = async (node, widget, message) => {
  widget.div.innerHTML = ``

  const width = node.size[0] * 0.5 - 12

  let height_add = 0

  for (let index = 0; index < message._images.length; index++) {
    const imgs = message._images[index]

    for (const img of imgs) {
      let url = api.apiURL(
        `/view?filename=${encodeURIComponent(img.filename)}&type=${
          img.type
        }&subfolder=${
          img.subfolder
        }${app.getPreviewFormatParam()}${app.getRandParam()}`
      )

      let image = await createImage(url)

      // 创建card
      let div = document.createElement('div')
      div.className = 'card'
      div.draggable = true

      div.ondragend = async event => {
        console.log('拖动停止')
        let url = div.querySelector('img').src

        let blob = await fetchImage(url)

        let imageNode = null
        // No image node selected: add a new one
        if (!imageNode) {
          const newNode = LiteGraph.createNode('LoadImage')
          newNode.pos = [...app.canvas.graph_mouse]
          imageNode = app.graph.add(newNode)
          app.graph.change()
        }

        // const blob = item.getAsFile();
        imageNode.pasteFile(blob)
      }

      div.setAttribute('data-scale', image.naturalHeight / image.naturalWidth)

      let h = (image.naturalHeight * width) / image.naturalWidth
      if (index % 2 === 0) height_add += h
      div.style = `width: ${width}px;height:${h}px;position: relative;margin: 4px;`

      div.innerHTML = `<a href="${url}" 
      data-pswp-width="${image.naturalWidth}" 
      data-pswp-height="${image.naturalHeight}" 
      target="_blank">
      <img src="${url}" style='width: 100%' alt="${message.prompts[index]}"/>
    </a>
    <p style="position: absolute;
            bottom: 0;
            left: 0;
            opacity: 0.6;
            background-color: var(--comfy-input-bg); 
            color: var(--descrip-text);
            margin: 0;
            font-size: 12px;
            padding: 5px;
            text-align: left;">${message.prompts[index]}</p>`
      widget.div.appendChild(div)
    }
  }

  node.size[1] = 98 + height_add
}

app.registerExtension({
  name: 'Mixlab.prompt.PromptImage',

  async beforeRegisterNodeDef (nodeType, nodeData, app) {
    if (nodeType.comfyClass == 'PromptImage') {
      const orig_nodeCreated = nodeType.prototype.onNodeCreated
      nodeType.prototype.onNodeCreated = function () {
        orig_nodeCreated?.apply(this, arguments)
        console.log('#orig_nodeCreated', this)
        const widget = {
          type: 'div',
          name: 'result',
          draw (ctx, node, widget_width, y, widget_height) {
            Object.assign(this.div.style, {
              ...get_position_style(ctx, widget_width, y, node.size[1]),
              flexWrap: 'wrap',
              justifyContent: 'space-between',
              // outline: '1px solid red',
              paddingLeft: '0px',
              width: widget_width + 'px'
            })
          }
        }

        widget.div = $el('div', {})
        widget.div.className = 'prompt_image_output'

        document.body.appendChild(widget.div)

        this.addCustomWidget(widget)

        initLightBox()

        const onRemoved = this.onRemoved
        this.onRemoved = () => {
          widget.div.remove()
          return onRemoved?.()
        }

        const onResize = this.onResize
        this.onResize = function () {
          // 缩放发生
          // console.log('##缩放发生', this.size)
          let w = this.size[0] * 0.5 - 12
          Array.from(widget.div.querySelectorAll('.card'), card => {
            card.style.width = `${w}px`
            card.style.height = `${
              w * parseFloat(card.getAttribute('data-scale'))
            }px`
          })
          return onResize?.apply(this, arguments)
        }

        // this.serialize_widgets = true //需要保存参数
      }

      const onExecuted = nodeType.prototype.onExecuted
      nodeType.prototype.onExecuted = async function (message) {
        onExecuted?.apply(this, arguments)
        console.log('#PromptImage', message.prompts, message._images)
        // window._mixlab_app_json = message.json
        try {
          let widget = this.widgets.filter(w => w.name === 'result')[0]
          widget.value = message
          _createResult(this, widget, { ...message })
        } catch (error) {
          console.log(error)
        }
      }

      this.serialize_widgets = true //需要保存参数
    }
  },
  async loadedGraphNode (node, app) {
    if (node.type === 'PromptImage') {
      // await sleep(0)
      let widget = node.widgets.filter(w => w.name === 'result')[0]
      console.log('widget.value', widget.value)

      initLightBox()

      let cards = widget.div.querySelectorAll('.card')
      if (cards.length == 0) node.size = [280, 120]
      if (widget.value) _createResult(node, widget, widget.value)
    }
  }
})
