import { app } from '../../scripts/app.js'
import { api } from '../../scripts/api.js'

function offsetDOMWidget(
    widget,
    ctx,
    node,
    widgetWidth,
    widgetY,
    height
  ) {
    const margin = 10
    const elRect = ctx.canvas.getBoundingClientRect()
    const transform = new DOMMatrix()
      .scaleSelf(
        elRect.width / ctx.canvas.width,
        elRect.height / ctx.canvas.height
      )
      .multiplySelf(ctx.getTransform())
      .translateSelf(0, widgetY + margin)
  
    const scale = new DOMMatrix().scaleSelf(transform.a, transform.d)
    Object.assign(widget.inputEl.style, {
      transformOrigin: '0 0',
      transform: scale,
      left: `${transform.e}px`,
      top: `${transform.d + transform.f}px`,
      width: `${widgetWidth}px`,
      height: `${(height || widget.parent?.inputHeight || 32) - margin}px`,
      position: 'absolute',
      background: !node.color ? '' : node.color,
      color: !node.color ? '' : 'white',
      zIndex: 5, //app.graph._nodes.indexOf(node),
    })
  }

  export const hasWidgets = (node) => {
    if (!node.widgets || !node.widgets?.[Symbol.iterator]) {
      return false
    }
    return true
  }

  export const cleanupNode = (node) => {
    if (!hasWidgets(node)) {
      return
    }
  
    for (const w of node.widgets) {
      if (w.canvas) {
        w.canvas.remove()
      }
      if (w.inputEl) {
        w.inputEl.remove()
      }
      // calls the widget remove callback
      w.onRemoved?.()
    }
  }

const CreatePreviewElement = (name, val, format) => {
  const [type] = format.split('/')  
  const w = {
      name,
      type,
      value: val,
      draw: function (ctx, node, widgetWidth, widgetY, height) {
        const [cw, ch] = this.computeSize(widgetWidth)
        offsetDOMWidget(this, ctx, node, widgetWidth, widgetY, ch)
      },
      computeSize: function (_) {
        const ratio = this.inputRatio || 1
        const width = Math.max(220, this.parent.size[0])
        return [width, (width / ratio + 10)]
      },
      onRemoved: function () {
        if (this.inputEl) {
          this.inputEl.remove()
        }
      },
    }

    w.inputEl = document.createElement(type === 'video' ? 'video' : 'img')
    w.inputEl.src = w.value
    if (type === 'video') {
      w.inputEl.setAttribute('type', 'video/webm');
      w.inputEl.autoplay = true
      w.inputEl.loop = true
      w.inputEl.controls = false;
    }
    w.inputEl.onload = function () {
      w.inputRatio = w.inputEl.naturalWidth / w.inputEl.naturalHeight
    }
    document.body.appendChild(w.inputEl)
    return w
  }

const gif_preview = {
    name: 'efficiency.gif_preview',
    async beforeRegisterNodeDef(nodeType, nodeData, app) {
        switch (nodeData.name) {
            case 'KSampler (Efficient)':{
                const onExecuted = nodeType.prototype.onExecuted
                nodeType.prototype.onExecuted = function (message) {
                const prefix = 'ad_gif_preview_'
                const r = onExecuted ? onExecuted.apply(this, message) : undefined

                if (this.widgets) {
                    const pos = this.widgets.findIndex((w) => w.name === `${prefix}_0`)
                    if (pos !== -1) {
                      for (let i = pos; i < this.widgets.length; i++) {
                        this.widgets[i].onRemoved?.()
                    }
                    this.widgets.length = pos
                    }
                    if (message?.gifs) {
                      message.gifs.forEach((params, i) => {
                        const previewUrl = api.apiURL(
                          '/view?' + new URLSearchParams(params).toString()
                        )
                  const w = this.addCustomWidget(
                    CreatePreviewElement(`${prefix}_${i}`, previewUrl, params.format || 'image/gif')
                  )
                  w.parent = this
                  })
                 }
                  const onRemoved = this.onRemoved
                  this.onRemoved = () => {
                    cleanupNode(this)
                    return onRemoved?.()
                  }
                }
                if (message?.gifs && message.gifs.length > 0) {
                    this.setSize([this.size[0], this.computeSize([this.size[0], this.size[1]])[1]]);
                }
                return r
                }
                break
              }
        }
    }
}

app.registerExtension(gif_preview)
