import { TextEditor } from './text_editor';
import { ImageEditor } from './image_editor';
import AddText from './add_text.js';
import AddImage from './add_image.js';

export class ContentContainer {
  constructor(options) {
    this.pageViewer = options.pageViewer
    this.eventBus = options.eventBus
    this.pageIndex = options.pageIndex
    this.pagePtr = options.pagePtr
    this.messageHandler = options.messageHandler
    this.pageDiv = options.pageDiv
    this.viewport = options.viewport
    this.scale = options.scale
    this.$t = options.$t
    this.historyManager = options.contentEditHistoryManager

    this.destroyed = false
    this.rendered = false
    this.isRendering = false
    this.frameEditorList = []
    this.tool = this.pageViewer.tool || ''
    this.color = this.pageViewer.color || ''
    this._selectedFrameIndex = -1

    this.onHandleTool = this.handleTool.bind(this)
    this.onKeydown = this.handleKeyDown.bind(this)
  }

  async init() {
    await this.update()

    document.addEventListener('keydown', this.onKeydown)
    this.eventBus._on('toolChanged', this.onHandleTool)
    this.render()
  }

  async update() {
    const { editPagePtr } = await this.messageHandler.sendWithPromise('InitEditPage', {
      pagePtr: this.pagePtr
    })
    this.editPagePtr = editPagePtr

    const result = await this.messageHandler.sendWithPromise('BeginEdit', {
      editPagePtr: this.editPagePtr,
      type: 1 | 2
    })
    if (result && result.code) {
      console.log(result.message)
      alert(result.message)
      return false
    }

    this.tool = this.pageViewer.tool || ''
  }

  async render () {
    if (this.contentContainer) {
      return;
    }
    const rendering = this.isRendering
    this.isRendering = true

    const contentContainer = document.createElement('div')
    contentContainer.className = 'contentContainer'
    this.contentContainer = contentContainer
    this.pageDiv.append(this.contentContainer)

    this.frameEditorList.forEach(editor => {
      editor.removeViewer()
    })
    this.frameEditorList.length = 0

    try {
      const editAreaCount = await this.messageHandler.sendWithPromise('GetEditAreaCount', this.editPagePtr)
      for (let i = 0; i < editAreaCount; i++) {
        if (rendering) break

        const editAreaPtr = await this.messageHandler.sendWithPromise('GetEditArea', {
          editPagePtr: this.editPagePtr,
          index: i
        })
        if (!editAreaPtr) continue

        const isTextPtr = await this.messageHandler.sendWithPromise('IsTextArea', editAreaPtr)
        if (isTextPtr) {
          const frameEditor = new TextEditor({
            eventBus: this.eventBus,
            contentContainer: this,
            container: this.contentContainer,
            pagePtr: this.pagePtr,
            editPagePtr: this.editPagePtr,
            editAreaPtr,
            editAreaIndex: i,
            viewport: this.pageViewer.viewport,
            scale: this.pageViewer.scale,
            messageHandler: this.messageHandler,
            pageViewer: this.pageViewer,
            hidden: this.tool === 'addImage'
          })
          this.frameEditorList.push(frameEditor)
          continue
        }

        const isImagePtr = await this.messageHandler.sendWithPromise('IsImageArea', editAreaPtr)
        if (isImagePtr) {
          const frameEditor = new ImageEditor({
            eventBus: this.eventBus,
            contentContainer: this,
            container: this.contentContainer,
            pagePtr: this.pagePtr,
            editPagePtr: this.editPagePtr,
            editAreaPtr,
            editAreaIndex: i,
            viewport: this.pageViewer.viewport,
            scale: this.pageViewer.scale,
            messageHandler: this.messageHandler,
            pageViewer: this.pageViewer,
            $t: this.$t,
            hidden: this.tool === 'addText'
          })
          this.frameEditorList.push(frameEditor)
        }
      }
    } finally {
      this.isRendering = false
    }

    if (this.tool === 'addText') {
      this.addTextManager()
    }
    if (this.tool === 'addImage') {
      this.addImageManager()
    }

    this.destroyed = false
    this.rendered = true
  }

  show () {
    this.contentContainer.style.display = 'block'
  }

  hide () {
    this.contentContainer.style.display = 'none'

    if (this.textManager) {
      this.textManager.tool = ''
      this.textManager.reset()
    }
    if (this.imageManager) {
      this.imageManager.tool = ''
      this.imageManager.reset()
    }
  }

  cancel () {
    if (this.destroyed || !this.rendered) return

    this.contentContainer?.remove()
    this.contentContainer = null

    if (this.textManager) {
      this.textManager.tool = ''
      this.textManager.reset()
    }
    if (this.imageManager) {
      this.imageManager.tool = ''
      this.imageManager.reset()
    }

  }

  destroy () {
    if (this.destroyed || !this.rendered) return

    this.contentContainer?.remove()
    this.contentContainer = null

    if (this.textManager) {
      this.textManager.tool = ''
      this.textManager.reset()
    }
    if (this.imageManager) {
      this.imageManager.tool = ''
      this.imageManager.reset()
    }

    this.destroyed = true

    this.eventBus._off('toolChanged', this.onHandleTool)
    document.removeEventListener('keydown', this.onKeydown)

    this.messageHandler.sendWithPromise('ClearEditPage', this.editPagePtr)
  }

  handleTool({
    tool,
    color
  }) {
    this.tool = tool
    this.color = color

    if (this.textManager) {
      this.textManager.tool = tool
      this.textManager.color = color
    }
    if (this.imageManager) {
      this.imageManager.tool = tool
      this.imageManager.color = color
    }

    if (tool === 'addText') {
      if (this.imageManager) {
        this.imageManager.tool = ''
        this.imageManager.reset()
      }
      this.addTextManager()
    }
    if (tool === 'addImage') {
      if (this.textManager) {
        this.textManager.tool = ''
        this.textManager.reset()
      }
      this.addImageManager()
    }

    const toolMap = {
      addText: 'text',
      addImage: 'image'
    }
    const type = toolMap[this.tool] ? toolMap[this.tool] : ''
    this.eventBus.dispatch('showContentEditorType', type)
  }

  addTextManager () {
    if (this.textManager) {
      this.textManager.init()
    } else {
      this.textManager = new AddText({
        tool: this.tool,
        color: this.color,
        container: this.pageDiv,
        pageViewer: this.pageViewer,
        viewport: this.pageViewer.viewport,
        scale: this.pageViewer.scale,
        page: this.page,
        eventBus: this.eventBus,
        contentContainer: this
      })
    }
  }

  addImageManager () {
    if (this.imageManager) {
      this.imageManager.init()
    } else {
      this.imageManager = new AddImage({
        tool: this.tool,
        color: this.color,
        container: this.pageDiv,
        pageViewer: this.pageViewer,
        viewport: this.pageViewer.viewport,
        scale: this.pageViewer.scale,
        page: this.page,
        eventBus: this.eventBus,
        contentContainer: this,
        $t: this.$t
      })
    }
  }

  // 添加编辑区域
  async addTextEditor (data) {
    const { rect, fontData, alignType } = data
    const editAreaPtr = await this.messageHandler.sendWithPromise('CreateNewTextArea', {
      pagePtr: this.pagePtr,
      editPagePtr: this.editPagePtr,
      rect,
      fontData,
      alignType
    })
    if (!editAreaPtr) return

    const frameEditor = new TextEditor({
      eventBus: this.eventBus,
      contentContainer: this,
      container: this.contentContainer,
      pagePtr: this.pagePtr,
      editPagePtr: this.editPagePtr,
      editAreaPtr,
      editAreaIndex: this.frameEditorList.length,
      viewport: this.pageViewer.viewport,
      scale: this.pageViewer.scale,
      messageHandler: this.messageHandler,
      newAdd: true,
      pageViewer: this.pageViewer
    })
    this.frameEditorList.push(frameEditor)
  }

  // 添加图片区域
  async addImageEditor (data) {
    const { rect, imageBase64 } = data
    const editAreaPtr = await this.messageHandler.sendWithPromise('CreateNewImageAreaByStream', {
      pagePtr: this.pagePtr,
      editPagePtr: this.editPagePtr,
      rect,
      imageBase64
    })

    if (!editAreaPtr) return

    const frameEditor = new ImageEditor({
      eventBus: this.eventBus,
      contentContainer: this,
      container: this.contentContainer,
      pagePtr: this.pagePtr,
      editPagePtr: this.editPagePtr,
      editAreaPtr,
      editAreaIndex: this.frameEditorList.length,
      viewport: this.pageViewer.viewport,
      scale: this.pageViewer.scale,
      messageHandler: this.messageHandler,
      newAdd: true,
      pageViewer: this.pageViewer,
      $t: this.$t
    })
    this.frameEditorList.push(frameEditor)
  }

  get selectedFrameIndex () {
    return this._selectedFrameIndex
  }

  set selectedFrameIndex (index) {
    this._selectedFrameIndex = index
  }

  removeEditor (index) {
    this.frameEditorList.splice(index, 1)
    this.frameEditorList.forEach((editor, i) => editor.editAreaIndex = i)
  }

  handleKeyDown (e) {
    const selectedEditor = this.frameEditorList[this._selectedFrameIndex]
    if (!selectedEditor || selectedEditor.state !== 1 || document.querySelector('.n-color-picker-panel') || e.target.className === 'n-input__input-el') return

    const keyCode = e.keyCode || e.which
    if (keyCode === 8 || keyCode === 46) { // 8 delete键，46 backspace键
      selectedEditor.remove()
    }
  }

  // undo/redo
  async handleResetOperate(op) {
    if (op === 'undo') {
      const res = await this.historyManager.undo()
      // await this.updateFrameEditor(res)

    } else if (op === 'redo') {
      const res = await this.historyManager.redo()
      // await this.updateFrameEditor(res)
    }
  }

  // 修改后添加到undo列表
  async handleOperateList(data) {
    const canUndo = await this.historyManager.canUndo(data)
    if (!canUndo) return
    this.eventBus.dispatch('undoRedoStatusChanged')
    this.historyManager.undoList.push(data)
    this.historyManager.redoList.length = 0

    this.eventBus.dispatch('changeOperateList', {
      undoListLength: this.historyManager.undoList.length,
      redoListLength: this.historyManager.redoList.length
    })
    this.eventBus.dispatch('isContentEditModyfied', true)
  }

  // undo/redo后，更新视图
  async updateFrameEditor (res) {
    const { editAreaPtr, editCharPlace } = res

    const editor = this.frameEditorList.find(item => item.editAreaPtr === editAreaPtr)
    if (editor) {
      editor.updateCanvasAfterUndoRedo()
      editor.type === 'text' && (editCharPlace.CharIndex !== -1 || editCharPlace.LineIndex !== -1 || editCharPlace.RunIndex !== -1 || editCharPlace.SectionIndex !== -1 ) && editor.updateCursorLine(editCharPlace)
      return
    }

    const newFrameEditorList = []
    const editAreaCount = await this.messageHandler.sendWithPromise('GetEditAreaCount', this.editPagePtr)

    for (let i = 0; i < editAreaCount; i++) {
      const editAreaPtr = await this.messageHandler.sendWithPromise('GetEditArea', {
        editPagePtr: this.editPagePtr,
        index: i
      })
      if (!editAreaPtr) continue

      let frameEditor
      if (await this.messageHandler.sendWithPromise('IsTextArea', editAreaPtr)) {
        frameEditor = new TextEditor({
          eventBus: this.eventBus,
          contentContainer: this,
          container: this.contentContainer,
          pagePtr: this.pagePtr,
          editPagePtr: this.editPagePtr,
          editAreaPtr,
          editAreaIndex: i,
          viewport: this.pageViewer.viewport,
          scale: this.pageViewer.scale,
          messageHandler: this.messageHandler,
          pageViewer: this.pageViewer,
          hidden: this.tool === 'addImage',
          isUpdate: true
        })
      } else if (await this.messageHandler.sendWithPromise('IsImageArea', editAreaPtr)) {
        frameEditor = new ImageEditor({
          eventBus: this.eventBus,
          contentContainer: this,
          container: this.contentContainer,
          pagePtr: this.pagePtr,
          editPagePtr: this.editPagePtr,
          editAreaPtr,
          editAreaIndex: i,
          viewport: this.pageViewer.viewport,
          scale: this.pageViewer.scale,
          messageHandler: this.messageHandler,
          pageViewer: this.pageViewer,
          $t: this.$t,
          hidden: this.tool === 'addText',
          isUpdate: true
        })
      }
      frameEditor && newFrameEditorList.push(frameEditor)
    }

    this.frameEditorList.forEach(async editor => {
      await editor.updateCanvas(null, true)
      editor.removeViewer()
    })
    this.frameEditorList.length = 0
    this.frameEditorList = newFrameEditorList
  }
}
