import JSZip from 'jszip'
import xmlConvert from 'xml-js'
import {
  getTextFromHtml,
  imgToDataUrl,
  parseDataUrl,
  getImageSize
} from '../utils/index'

//  解析.xmind文件
const parseXmindFile = file => {
  return new Promise((resolve, reject) => {
    JSZip.loadAsync(file).then(
      async zip => {
        try {
          let content = ''
          if (zip.files['content.json']) {
            let json = await zip.files['content.json'].async('string')
            content = await transformXmind(json, zip.files)
          } else if (zip.files['content.xml']) {
            let xml = await zip.files['content.xml'].async('string')
            let json = xmlConvert.xml2json(xml)
            content = transformOldXmind(json)
          }
          if (content) {
            resolve(content)
          } else {
            reject(new Error('解析失败'))
          }
        } catch (error) {
          reject(error)
        }
      },
      e => {
        reject(e)
      }
    )
  })
}

//  转换xmind数据
const transformXmind = async (content, files) => {
  let data = JSON.parse(content)[0]
  let nodeTree = data.rootTopic
  let newTree = {}
  let waitLoadImageList = []
  let walk = async (node, newNode) => {
    newNode.data = {
      // 节点内容
      text: node.title
    }
    // 节点备注
    if (node.notes) {
      let notesData = node.notes.realHTML || node.notes.plain
      newNode.data.note = notesData ? notesData.content || '' : ''
    }
    // 超链接
    if (node.href && /^https?:\/\//.test(node.href)) {
      newNode.data.hyperlink = node.href
    }
    // 标签
    if (node.labels && node.labels.length > 0) {
      newNode.data.tag = node.labels
    }
    // 图片
    if (node.image && /\.(jpg|jpeg|png|gif|webp)$/.test(node.image.src)) {
      try {
        // 处理异步逻辑
        let resolve = null
        let promise = new Promise(_resolve => {
          resolve = _resolve
        })
        waitLoadImageList.push(promise)
        // 读取图片
        let imageType = /\.([^.]+)$/.exec(node.image.src)[1]
        let imageBase64 =
          `data:image/${imageType};base64,` +
          (await files['resources/' + node.image.src.split('/')[1]].async(
            'base64'
          ))
        newNode.data.image = imageBase64
        // 如果图片尺寸不存在
        if (!node.image.width && !node.image.height) {
          let imageSize = await getImageSize(imageBase64)
          newNode.data.imageSize = {
            width: imageSize.width,
            height: imageSize.height
          }
        } else {
          newNode.data.imageSize = {
            width: node.image.width,
            height: node.image.height
          }
        }
        resolve()
      } catch (error) {
        console.log(error)
        resolve()
      }
    }
    // 子节点
    newNode.children = []
    if (
      node.children &&
      node.children.attached &&
      node.children.attached.length > 0
    ) {
      node.children.attached.forEach(item => {
        let newChild = {}
        newNode.children.push(newChild)
        walk(item, newChild)
      })
    }
  }
  walk(nodeTree, newTree)
  await Promise.all(waitLoadImageList)
  return newTree
}

//  转换旧版xmind数据，xmind8
const transformOldXmind = content => {
  let data = JSON.parse(content)
  let elements = data.elements
  let root = null
  let getRoot = arr => {
    for (let i = 0; i < arr.length; i++) {
      if (!root && arr[i].name === 'topic') {
        root = arr[i]
        return
      }
    }
    arr.forEach(item => {
      getRoot(item.elements)
    })
  }
  getRoot(elements)
  let newTree = {}
  let getItemByName = (arr, name) => {
    return arr.find(item => {
      return item.name === name
    })
  }
  let walk = (node, newNode) => {
    let nodeElements = node.elements
    newNode.data = {
      // 节点内容
      text: getItemByName(nodeElements, 'title').elements[0].text
    }
    try {
      // 节点备注
      let notesElement = getItemByName(nodeElements, 'notes')
      if (notesElement) {
        newNode.data.note =
          notesElement.elements[0].elements[0].elements[0].text
      }
    } catch (error) {
      console.log(error)
    }
    try {
      // 超链接
      if (
        node.attributes &&
        node.attributes['xlink:href'] &&
        /^https?:\/\//.test(node.attributes['xlink:href'])
      ) {
        newNode.data.hyperlink = node.attributes['xlink:href']
      }
    } catch (error) {
      console.log(error)
    }
    try {
      // 标签
      let labelsElement = getItemByName(nodeElements, 'labels')
      if (labelsElement) {
        newNode.data.tag = labelsElement.elements.map(item => {
          return item.elements[0].text
        })
      }
    } catch (error) {
      console.log(error)
    }
    // 子节点
    newNode.children = []
    let _children = getItemByName(nodeElements, 'children')
    if (_children && _children.elements && _children.elements.length > 0) {
      _children.elements.forEach(item => {
        if (item.name === 'topics') {
          item.elements.forEach(item2 => {
            let newChild = {}
            newNode.children.push(newChild)
            walk(item2, newChild)
          })
        } else {
          let newChild = {}
          newNode.children.push(newChild)
          walk(item, newChild)
        }
      })
    }
  }
  walk(root, newTree)
  return newTree
}

// 数据转换为xmind文件
const transformToXmind = async (data, name) => {
  const id = 'simpleMindMap_' + Date.now()
  const imageList = []
  // 转换核心数据
  let newTree = {}
  let waitLoadImageList = []
  let walk = async (node, newNode, isRoot) => {
    let newData = {
      structureClass: 'org.xmind.ui.logic.right',
      title: getTextFromHtml(node.data.text), // 节点文本
      children: {
        attached: []
      }
    }
    // 备注
    if (node.data.note !== undefined) {
      newData.notes = {
        realHTML: {
          content: node.data.note
        },
        plain: {
          content: node.data.note
        }
      }
    }
    // 超链接
    if (node.data.hyperlink !== undefined) {
      newData.href = node.data.hyperlink
    }
    // 标签
    if (node.data.tag !== undefined) {
      newData.labels = node.data.tag || []
    }
    // 图片
    if (node.data.image) {
      try {
        // 处理异步逻辑
        let resolve = null
        let promise = new Promise(_resolve => {
          resolve = _resolve
        })
        waitLoadImageList.push(promise)
        let imgName = ''
        let imgData = node.data.image
        // 网络图片要先转换成data:url
        if (/^https?:\/\//.test(node.data.image)) {
          imgData = await imgToDataUrl(node.data.image)
        }
        // 从data:url中解析出图片类型和base64
        let dataUrlRes = parseDataUrl(imgData)
        imgName = 'image_' + imageList.length + '.' + dataUrlRes.type
        imageList.push({
          name: imgName,
          data: dataUrlRes.base64
        })
        newData.image = {
          src: 'xap:resources/' + imgName,
          width: node.data.imageSize.width,
          height: node.data.imageSize.height
        }
        resolve()
      } catch (error) {
        console.log(error)
        resolve()
      }
    }
    // 样式
    // 暂时不考虑样式
    if (isRoot) {
      newData.class = 'topic'
      newNode.id = id
      newNode.class = 'sheet'
      newNode.title = name
      newNode.extensions = []
      newNode.topicPositioning = 'fixed'
      newNode.topicOverlapping = 'overlap'
      newNode.coreVersion = '2.100.0'
      newNode.rootTopic = newData
    } else {
      Object.keys(newData).forEach(key => {
        newNode[key] = newData[key]
      })
    }
    if (node.children && node.children.length > 0) {
      node.children.forEach(child => {
        let newChild = {}
        walk(child, newChild)
        newData.children.attached.push(newChild)
      })
    }
  }
  walk(data, newTree, true)
  await Promise.all(waitLoadImageList)
  const contentData = [newTree]
  // 创建压缩包
  const zip = new JSZip()
  zip.file('content.json', JSON.stringify(contentData))
  zip.file(
    'metadata.json',
    `{"modifier":"","dataStructureVersion":"1","layoutEngineVersion":"2","activeSheetId":"${id}"}`
  )
  const manifestData = {
    'file-entries': { 'content.json': {}, 'metadata.json': {} }
  }
  // 图片
  if (imageList.length > 0) {
    imageList.forEach(item => {
      manifestData['file-entries']['resources/' + item.name] = {}
      const img = zip.folder('resources')
      img.file(item.name, item.data, { base64: true })
    })
  }
  zip.file('manifest.json', JSON.stringify(manifestData))
  const zipData = await zip.generateAsync({ type: 'blob' })
  return zipData
}

export default {
  parseXmindFile,
  transformXmind,
  transformOldXmind,
  transformToXmind
}
