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

function base64ToBlobFromURL (base64URL, contentType) {
  return fetch(base64URL).then(response => response.blob())
}

async function uploadImage (blob, fileType = '.svg', filename) {
  // const blob = await (await fetch(src)).blob();
  const body = new FormData()
  body.append(
    'image',
    new File([blob], (filename || new Date().getTime()) + fileType)
  )

  const resp = await api.fetchApi('/upload/image', {
    method: 'POST',
    body
  })

  // console.log(resp)
  let data = await resp.json()

  return data
}

// 上传得到url
async function uploadBase64ToFile (base64) {
  let bg_blob = await base64ToBlobFromURL(base64)
  let url = await uploadImage(bg_blob, '.png')
  return url
}

class Visualizer {
  constructor (node, container, visualSrc) {
    this.node = node

    this.iframe = document.createElement('iframe')
    Object.assign(this.iframe, {
      scrolling: 'no',
      overflow: 'hidden'
    })
    this.iframe.src = '/mixlab/app/' + visualSrc + '.html'
    // this.iframe.width="300";
    // this.iframe.height="400";

    console.log('#Visualizer', container, this.iframe)
    container.appendChild(this.iframe)
  }

  updateVisual (params) {
    console.log('#updateVisual', params, this.iframe)
    // const iframeDocument = this.iframe.contentWindow.document
    // const previewScript = iframeDocument.getElementById('visualizer')
    // previewScript.setAttribute(
    //   'reference_image',
    //   JSON.stringify(params.reference_image)
    // )
    // previewScript.setAttribute('depth_map', JSON.stringify(params.depth_map))
    // Update the reference image and depth map
    this.iframe.contentWindow.postMessage(params, '*')
  }

  remove () {
    this.container.remove()
  }
}

function createVisualizer (node, inputName, typeName, inputData, app) {
  node.name = inputName

  const widget = {
    type: typeName,
    name: 'preview3d',
    callback: () => {},
    draw: function (ctx, node, widgetWidth, widgetY, widgetHeight) {
      const margin = 10
      const top_offset = 5
      const visible = app.canvas.ds.scale > 0.3 && this.type === typeName
      const w = widgetWidth - margin * 4
      const clientRectBound = ctx.canvas.getBoundingClientRect()
      const transform = new DOMMatrix()
        .scaleSelf(
          clientRectBound.width / ctx.canvas.width,
          clientRectBound.height / ctx.canvas.height
        )
        .multiplySelf(ctx.getTransform())
        .translateSelf(margin, margin + widgetY)

      Object.assign(this.visualizer.style, {
        left: `${transform.a * margin + transform.e + 0}px`,
        top: `${transform.d + transform.f + top_offset}px`,
        width: `${w * transform.a}px`,
        height: `${(w * transform.a * 4) / 3 - margin * 5 * transform.d}px`,
        // height: `${
        //   w * transform.d - widgetHeight - margin * 15 * transform.d
        // }px`,
        position: 'absolute',
        overflow: 'hidden',
        zIndex: app.graph._nodes.indexOf(node)
      })

      Object.assign(this.visualizer.children[0].style, {
        transformOrigin: '50% 50%',
        width: '100%',
        height: '100%',
        border: '0 none'
      })

      this.visualizer.hidden = !visible
    }
  }

  const container = document.createElement('div')
  container.id = `Comfy3D_${inputName}`

  node.visualizer = new Visualizer(node, container, typeName)
  widget.visualizer = container
  widget.parent = node

  document.body.appendChild(widget.visualizer)

  node.addCustomWidget(widget)

  node.updateParameters = params => {
    // console.log('#updateParameters', params)
    params.id = node.id
    // node.visualizer = new Visualizer(node, container, typeName)
    node.visualizer.updateVisual(params)
  }

  // Events for drawing backgound
  node.onDrawBackground = function (ctx) {
    if (!this.flags.collapsed) {
      node.visualizer.iframe.hidden = false
    } else {
      node.visualizer.iframe.hidden = true
    }
  }

  // Make sure visualization iframe is always inside the node when resize the node
  node.onResize = function () {
    let [w, h] = this.size
    if (w <= 300) w = 300
    if (h <= 400) h = 400

    if (w > 300) {
      h = Math.round((w * 4) / 3)
    }

    this.size = [w, h]
  }

  // Events for remove nodes
  node.onRemoved = () => {
    for (let w in node.widgets) {
      if (node.widgets[w].visualizer) {
        node.widgets[w].visualizer.remove()
      }
    }
  }

  return {
    widget: widget
  }
}

function registerVisualizer (nodeType, nodeData, nodeClassName, typeName) {
  if (nodeData.name == nodeClassName) {
    const onNodeCreated = nodeType.prototype.onNodeCreated

    nodeType.prototype.onNodeCreated = async function () {
      const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined

      let Preview3DNode = app.graph._nodes.filter(
        wi => wi.type == nodeClassName
      )
      let nodeName = `Preview3DNode_${Preview3DNode.length}`

      const result = await createVisualizer.apply(this, [
        this,
        nodeName,
        typeName,
        {},
        app
      ])

      this.setSize([300, 400])

      return r
    }

    nodeType.prototype.onExecuted = async function (message) {
      // Check if reference image and depth map are available
      console.log('#message', message)
      if (message.reference_image && message.depth_map) {
        const params = {}
        params.reference_image = message.reference_image[0]
        params.depth_map = message.depth_map[0]
        this.updateParameters(params)
      }
    }
  }
}

app.registerExtension({
  name: 'Mixlab.nodes.depthviewer',

  async beforeRegisterNodeDef (nodeType, nodeData, app) {
    registerVisualizer(nodeType, nodeData, 'DepthViewer', 'threeVisualizer')
  },
  nodeCreated (node, app) {
    //数据延迟？？
    setTimeout(() => {
      let widget = node.widgets?.filter(w => w.name == 'preview3d')[0]
      let framesWidget = node.widgets?.filter(w => w.name == 'frames')[0]

      if (node.type === 'DepthViewer' && widget) {
        let nodeId = node.id
        //延迟才能获得this.id
        widget.visualizer.querySelector('iframe').src += '?id=' + nodeId
        // console.log('DepthViewer',widget)
        window.addEventListener('message', async event => {
          // 检查消息的来源，确保消息来自可信的源
          console.log(event)
          const { id, imgs } = event.data
          if (id == nodeId) {
            framesWidget.value = { images: [] }

            for (const f of imgs) {
              let file = await uploadBase64ToFile(f)
              framesWidget.value.images.push(file)
            }
            // framesWidget.value.base64 = frames
            framesWidget.value._seed = Math.random()
            node.title = 'Input #' + imgs.length
          }
        })
      }
    }, 1000)
  }
})
