import { app } from '../../../scripts/app.js'
import { $el } from '../../../scripts/ui.js'
import {
  loadExternalScript,
  updateLLMAPIKey,
  get_position_style,
  getLocalData
} from './common.js'

loadExternalScript('/mixlab/app/lib/pickr.min.js')

function hexToRGBA (hexColor) {
  var hex = hexColor.replace('#', '')
  var r = parseInt(hex.substring(0, 2), 16)
  var g = parseInt(hex.substring(2, 4), 16)
  var b = parseInt(hex.substring(4, 6), 16)

  // 获取透明度的十六进制值
  var alphaHex = hex.substring(6)

  // 将透明度的十六进制值转换为十进制值
  var alpha = parseInt(alphaHex, 16) / 255

  return [r, g, b, alpha]
}

app.registerExtension({
  name: 'Mixlab.utils.Color',
  init () {
    $el('link', {
      rel: 'stylesheet',
      href: '/mixlab/app/lib/classic.min.css',
      parent: document.head
    })

    $el('style', {
      textContent: `
      .pickr{
        display: flex;
        justify-content: center;
        align-items: center;
      }
				.pickr .pcr-button {
					width: 56px;
          height: 56px;
          outline: 1px solid white;
				}
				 
			`,
      parent: document.body
    })
  },
  async getCustomWidgets (app) {
    return {
      TCOLOR (node, inputName, inputData, app) {
        // console.log('##node', node)
        const widget = {
          type: inputData[0], // the type, CHEESE
          name: inputName, // the name, slice
          size: [128, 32], // a default size
          draw (ctx, node, width, y) {},
          computeSize (...args) {
            return [128, 32] // a method to compute the current size of the widget
          },
          async serializeValue (nodeId, widgetIndex) {
            // let data = getLocalData('_mixlab_utils_color')
            // let hex = data[node.id] || '#000000'
            let hex = widget.value || '#000000'
            let [r, g, b, a] = hexToRGBA(hex)
            return {
              hex,
              r,
              g,
              b,
              a
            }
          }
        }
        //  widget.something = something;          // maybe adds stuff to it
        node.addCustomWidget(widget) // adds it to the node
        return widget // and returns it.
      }
    }
  },

  async beforeRegisterNodeDef (nodeType, nodeData, app) {
    if (nodeType.comfyClass == 'Color') {
      const orig_nodeCreated = nodeType.prototype.onNodeCreated
      nodeType.prototype.onNodeCreated = function () {
        orig_nodeCreated?.apply(this, arguments)

        // console.log('Color nodeData', this.div)

        const widget = {
          type: 'div',
          name: 'input_color',
          draw (ctx, node, widget_width, y, widget_height) {
            Object.assign(
              this.div.style,
              get_position_style(ctx, widget_width, 44, node.size[1])
            )
            // console.log('draw',y,node.widgets[0].last_y)
          }
        }

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

        document.body.appendChild(widget.div)

        const inputDiv = () => {
          let div = document.createElement('div')
          div.id = `color_picker_${this.id}`
          return div
        }

        let inputColor = inputDiv('_mixlab_utils_color', 'Color', '#000000')

        widget.div.appendChild(inputColor)

        this.addCustomWidget(widget)

        const pickr = Pickr.create({
          el: `#${inputColor.id}`,
          theme: 'classic', // or 'monolith', or 'nano'
          // closeOnScroll: true,
          default: '#000000',
          swatches: [
            'rgba(244, 67, 54, 1)',
            'rgba(233, 30, 99, 0.95)',
            'rgba(156, 39, 176, 0.9)',
            'rgba(103, 58, 183, 0.85)',
            'rgba(63, 81, 181, 0.8)',
            'rgba(33, 150, 243, 0.75)',
            'rgba(3, 169, 244, 0.7)',
            'rgba(0, 188, 212, 0.7)',
            'rgba(0, 150, 136, 0.75)',
            'rgba(76, 175, 80, 0.8)',
            'rgba(139, 195, 74, 0.85)',
            'rgba(205, 220, 57, 0.9)',
            'rgba(255, 235, 59, 0.95)',
            'rgba(255, 193, 7, 1)'
          ],

          components: {
            // Main components
            preview: true,
            opacity: true,
            hue: true,
            // Input / output Options
            interaction: {
              hex: true,
              rgba: true,
              hsla: true,
              hsva: true,
              cmyk: true,
              input: true,
              // clear: true,
              save: true,
              cancel: true
            }
          }
        })

        pickr
          .on('save', (color, instance) => {
            // console.log('Event: "save"', color.toHEXA().toString())
            // let data = getLocalData('_mixlab_utils_color')
            // data[this.id] = color.toHEXA().toString()
            // localStorage.setItem('_mixlab_utils_color', JSON.stringify(data))

            try {
              let tc = this.widgets.filter(w => w.type == 'TCOLOR')[0]
              tc.value = color.toHEXA().toString()
            } catch (error) {}
          })
          .on('cancel', instance => {
            pickr && pickr.hide()
          })
        this.pickr = pickr
        const handleMouseWheel = () => {
          try {
            this.pickr && this.pickr.hide()
          } catch (error) {}
        }

        document.addEventListener('wheel', handleMouseWheel)

        const onRemoved = this.onRemoved
        this.onRemoved = () => {
          inputColor.remove()
          widget.div.remove()

          try {
            this.pickr.destroyAndRemove()
            this.pickr = null
            document.removeEventListener('wheel', handleMouseWheel)
          } catch (error) {
            console.log(error)
          }

          return onRemoved?.()
        }

        this.serialize_widgets = true //需要保存参数
      }
    }
  },
  async loadedGraphNode (node, app) {
    // Fires every time a node is constructed
    // You can modify widgets/add handlers/etc here

    if (node.type === 'Color') {
      try {
        let TCOLOR = node.widgets.filter(w => w.type == 'TCOLOR')[0]

        setTimeout(() => node.pickr.setColor(TCOLOR.value || '#000000'), 1000)
      } catch (error) {}
    }
  }
})

app.registerExtension({
  name: 'Mixlab.utils.TextToNumber',
  async beforeRegisterNodeDef (nodeType, nodeData, app) {
    if (nodeType.comfyClass == 'TextToNumber') {
      const onExecuted = nodeType.prototype.onExecuted
      nodeType.prototype.onExecuted = function (message) {
        onExecuted?.apply(this, arguments)
        const random_number = this.widgets.filter(
          w => w.name === 'random_number'
        )[0]
        if (random_number.value === 'enable') {
          const n = this.widgets.filter(w => w.name === 'number')[0]
          n.value = message.num[0]
        }
        console.log('TextToNumber', random_number.value)
      }
    }
  }
})

const min_max = node => {
  if (node.widgets) {
    const min_value = node.widgets.filter(w => w.name === 'min_value')[0]
    const max_value = node.widgets.filter(w => w.name === 'max_value')[0]

    const number = node.widgets.filter(w => w.name === 'number')[0]
    if (number) {
      number.options.min = min_value.value
      number.options.max = max_value.value

      number.value = Math.min(number.options.max, number.value)
      number.value = Math.max(number.options.min, number.value)
    }

    if (min_value)
      min_value.callback = e => {
        number.options.min = e
        number.value = e
      }
    if (max_value)
      max_value.callback = e => {
        number.options.max = e
        number.value = e
      }
  }
}

app.registerExtension({
  name: 'Mixlab.utils.FloatSlider',
  async beforeRegisterNodeDef (nodeType, nodeData, app) {
    if (nodeType.comfyClass == 'FloatSlider') {
      const orig_nodeCreated = nodeType.prototype.onNodeCreated
      nodeType.prototype.onNodeCreated = function () {
        orig_nodeCreated?.apply(this, arguments)
        min_max(this)
      }
    }
  },
  async loadedGraphNode (node, app) {
    if (node.type === 'FloatSlider') {
      min_max(node)
    }
  }
})
app.registerExtension({
  name: 'Mixlab.utils.IntNumber',
  async beforeRegisterNodeDef (nodeType, nodeData, app) {
    if (nodeType.comfyClass == 'IntNumber') {
      const orig_nodeCreated = nodeType.prototype.onNodeCreated
      nodeType.prototype.onNodeCreated = function () {
        orig_nodeCreated?.apply(this, arguments)
        min_max(this)
      }
    }
  },
  async loadedGraphNode (node, app) {
    if (node.type === 'IntNumber') {
      min_max(node)
    }
  }
})

app.registerExtension({
  name: 'Mixlab.utils.TESTNODE_',
  async beforeRegisterNodeDef (nodeType, nodeData, app) {
    if (nodeType.comfyClass == 'TESTNODE_') {
      const onExecuted = nodeType.prototype.onExecuted
      nodeType.prototype.onExecuted = function (message) {
        onExecuted?.apply(this, arguments)
        console.log('##', message)
      }
    }
  }
})

app.registerExtension({
  name: 'Mixlab.utils.KeyInput',
  init () {},
  async getCustomWidgets (app) {
    return {
      KEY (node, inputName, inputData, app) {
        // console.log('##node', node)
        const widget = {
          type: inputData[0], // the type, CHEESE
          name: inputName, // the name, slice
          size: [128, 24], // a default size
          draw (ctx, node, width, y) {},
          computeSize (...args) {
            return [128, 32] // a method to compute the current size of the widget
          },
          async serializeValue (nodeId, widgetIndex) {
            let data = getLocalData('_mixlab_llm_api_key')
            return data[node.id] || 'by Mixlab'
          }
        }
        //  widget.something = something;          // maybe adds stuff to it
        node.addCustomWidget(widget) // adds it to the node
        return widget // and returns it.
      }
    }
  },

  async beforeRegisterNodeDef (nodeType, nodeData, app) {
    if (nodeType.comfyClass == 'KeyInput') {
      const orig_nodeCreated = nodeType.prototype.onNodeCreated
      nodeType.prototype.onNodeCreated = function () {
        orig_nodeCreated?.apply(this, arguments)

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

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

        document.body.appendChild(widget.div)

        const inputDiv = (key, placeholder) => {
          let div = document.createElement('div')
          div.style = `
          display: flex;
          align-items: center; 
          margin: 6px 8px;
          margin-top:0px;
          height:44px;
          width:220px; 
          `

          const ip = document.createElement('input')
          ip.type = 'password'
          ip.className = `${'comfy-multiline-input'} ${placeholder}`

          ip.placeholder = placeholder
          // ip.value = placeholder

          ip.style = `margin-left:8px;
            outline: none;
            border: none;
            padding:12px;
            width: 100%;
            `

          div.appendChild(ip)

          ip.addEventListener('change', () => {
            let data = getLocalData(key)
            data[this.id] = ip.value.trim()
            localStorage.setItem(key, JSON.stringify(data))
            updateLLMAPIKey(data[this.id])
          })

          return div
        }

        let inputKey = inputDiv('_mixlab_llm_api_key', 'Key')

        widget.div.appendChild(inputKey)

        this.addCustomWidget(widget)

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

        // const processMouseWheel=app.canvas.processMouseWheel
        // app.canvas.processMouseWheel=()=>{
        //   console.log(app.canvas.ds.scale)
        //   return processMouseWheel?.()
        // }

        this.serialize_widgets = true //需要保存参数
      }
    }
  },
  async loadedGraphNode (node, app) {
    if (node.type === 'KeyInput') {
      let widget = node.widgets.filter(w => w.div)[0]

      let apiKey = getLocalData('_mixlab_llm_api_key')

      let id = node.id
      if (widget.div.querySelector('.Key'))
        widget.div.querySelector('.Key').value = apiKey[id] || 'by Mixlab'

      if (apiKey[id]) updateLLMAPIKey(apiKey[id])
    }
  },
  nodeCreated (node, app) {
    //数据延迟？？
    setTimeout(() => {
      // console.log('#LoadImagesToBatch', node.type)
      if (node.type === 'KeyInput') {
        let widget = node.widgets.filter(w => w.div)[0]

        let apiKey = getLocalData('_mixlab_llm_api_key')

        let id = node.id

        if (widget.div.querySelector('.Key'))
          widget.div.querySelector('.Key').value = apiKey[id] || 'by Mixlab'

        if (apiKey[id]) updateLLMAPIKey(apiKey[id])
      }
    }, 1000)
  }
})
