import { rating, CATEGORIES } from '../../configuration/constants'
import { disableAllDescendantsDraggable } from '../../utils'

// far fa-star 为空心 fa fa-star 为实心
export default {
  // 组件名称
  name: rating,

  // 前面板 html 模板
  viewTemplate() {
    return `
      <div 
        class="${rating}-wrap" 
        data-gjs-type="${rating}"
      ></div>
    `
  },

  // 前面板 html 样式
  viewStyle() {
    return `
      <style>
        .${rating}-wrap {
          padding: 5px;
        }

        .${rating}-star {
          color: orange;
        }

      </style>
    `
  },

  // 编辑器右侧块管理器中显示属性配置
  blockOptions() {
    return {
      label: '评分',
      attributes: { class: 'fa fa-star' }
    };
  },

  // 后面板显示属性配置
  spOptions() {
    // 输入输出数据类型均为 { score: 5, total: 10 }
    return {
      label: '评分',
      icon: 'globe',
      docUrl: 'https://xuelangyun.yuque.com/docs/share/09c2015e-5401-4db8-bbf7-ec5379ba6351?# 《评分》',
      inPorts: [{
        uuid: 'in1',
        subType: 'json',
        description: {
          zh_CN: '输入评分'
        }
      }],
      outPorts: [{
        uuid: 'out1',
        subType: 'json',
        description: {
          zh_CN: '输出评分'
        }
      }]
    }
  },

  componentOptions() {
    return {
      name: rating,
      resizable: true,
      dmode: 'absolute',
      droppable: false,
      traits: [{
        name: 'starColor',
        label: '星星颜色',
        type: 'color',
        changeProp: 1
      }, {
        name: 'starCount',
        label: '星星总数',
        type: 'number',
        placeholder: '1-10',
        min: 1,
        max: 10,
        step: 1,
        changeProp: 1
      }, {
        name: 'rest',
        type: 'button',
        label: '重置',
        text: '重置所有高亮',
        full: true,
        command: editor => {
          // 将所有的星星全部不高亮
          const starWrapper = editor.getSelected().getEl()
          const stars = starWrapper.querySelectorAll(`.${rating}-star`)
          stars.forEach(s => {
            if (s.classList.contains('fa')) {
              s.classList.remove('fa')
              s.classList.add('far')
            }
          })
        }
      }],
      // 高亮颜色默认为橘色
      starColor: 'ffa500',
      // 默认星星总数为 5
      starCount: 5,
    }
  },

  onModelScript() {
    // 这里 this 为 model 组件
    const starColor = ('{[ starColor ]}').toString()
    const starCount = parseInt('{[ starCount ]}')
    const self = this
    const ratingBody = self.querySelector(`.rating-body`)
    const starNodes = self.querySelectorAll('.rating-star')
    const ratingTitle = self.querySelector('.rating-title')

    // 设置星星总数
    if (starCount >= starNodes.length) {
      // 如果比目前 star 数量多, 增加新的空白的 star
      const extraStar = document.createElement('span')
      // 设置 class
      extraStar.className = 'rating-star far fa-star'
      // 设置颜色
      extraStar.style.color = starColor

      // 将 需要的 star html 插入到尾端
      const extraStars = extraStar.outerHTML.repeat(parseInt(starCount) - starNodes.length)
      ratingBody.insertAdjacentHTML('beforeend', extraStars)

    } else {
      // 如果比目前的 star 少, 从后面开始往前移除
      for (let i = 0; i < starNodes.length; i++) {
        const starNode = starNodes[i]
        // 注意这里为 i+1, 因为 i 从 0 开始
        if ((i + 1) > starCount) {
          starNode.remove()
        }
      }
    }

    // 设置颜色, 以及不能拖动
    starNodes.forEach(s => {
      s.style.color = starColor
      // s.setAttribute('draggable', 'false')
    })

    // 设置无法拖动
    // ratingTitle.setAttribute('draggable', 'false')
    // ratingBody.setAttribute('draggable', 'false')

    // 监听输入端数据
    if (window.spSocket) {
      const eventName = `call-` + self.getAttribute('id');

      window.spSocket.subscribe({
        eventName,
        callback: function (res) {
          if (res.data.in1) {
            // input 数据为 { score: 5, total: 10 }
            const { score, total } = JSON.parse(res.data.in1)
            // 重新渲染星星
            self.querySelector('.rating-body').innerHTML = `
              ${`<span class="rating-star fa fa-star"></span>`.repeat(parseInt(score))}${`<span class="rating-star far fa-star"></span>`.repeat(parseInt(total) - parseInt(score))}
            `
            // 将数据作为输出发送
            window.spSocket.send({
              eventName,
              data: {
                success: true,
                out1: res.data.in1
              }
            });
          }
        }
      })
    }

    // 监听点击事件, 同时发送数据
    ratingBody.addEventListener('click', (e) => {
      const star = e.target
      // 需要做判断, star 是否被正确点击到, 否则可能触发到点击到其他 dom 层
      if (star.classList.contains('rating-star')) {
        const stars = star.parentNode.children
        const index = Array.prototype.indexOf.call(stars, star)

        // 高亮选中颜色
        for (let i = 0; i < stars.length; i++) {
          const s = stars[i]
          if (i <= index) {
            if (s.classList.contains('far')) {
              s.classList.remove('far')
              s.classList.add('fa')
            }
          } else {
            if (s.classList.contains('fa')) {
              s.classList.remove('fa')
              s.classList.add('far')
            }
          }
        }

        // 输出端发送数据
        if (window.spSocket) {
          const eventName = `call-` + self.getAttribute('id');
          // out 数据格式为 { score: 5, total: 10 }
          const out = {
            score: parseInt(index + 1),
            total: parseInt(stars.length)
          }
          window.spSocket.send({
            eventName: eventName,
            data: {
              success: true,
              out1: JSON.stringify(out)
            }
          });
        }
      }
    })
  },

  onViewInit() {
    const comps = this.model.get('components');
    // 拿到初始的星星总数
    const starCount = this.model.get('starCount')

    if (!comps.length) {
      comps.reset();
      comps.add(`
        <span class="${rating}-title">评分标签: </span>
        <span class="${rating}-body">
          ${`<span class="${rating}-star far fa-star"></span>`.repeat(starCount)}
        </span>
      `)
    }
    const evn = "change:starColor change:starCount"
    this.listenTo(this.model, evn, this.updateScript);
    this.listenTo(this.model, evn, this.em.handleUpdates.bind(this.em));

  },

  onViewRender(editor, el, model) {
    // 进行监听, 当移除一个节点的时候和 traits 里的 countStar 做绑定
    // 保证用户删除星星的时候 countStar 也对应更新
    const ratingBody = el.querySelector('.rating-body')
    this.observer = new MutationObserver((mutationsList, observer) => {
      for (let mutation of mutationsList) {
        if (mutation.type === 'childList') {
          const remainedStars = ratingBody.childNodes
          model.set('starCount', parseInt(remainedStars.length))
        }
      }
    })
    this.observer.observe(ratingBody, {
      attributes: true,
      childList: true,
      subtree: true
    })

    // 禁止子元素被拖动
    disableAllDescendantsDraggable(el)
  },

  onViewRemoved() {
    // 移除监听
    this.observer.disconnect()
  },
}