/* eslint no-alert: 0 */
import * as cornerstoneTools from 'cornerstone-tools'
const external = cornerstoneTools.external
const EVENTS = cornerstoneTools.EVENTS

const toolStyle = cornerstoneTools.toolStyle
const textStyle = cornerstoneTools.textStyle
const toolColors = cornerstoneTools.toolColors

const pointInsideBoundingBox = cornerstoneTools.import('util/pointInsideBoundingBox')
const lineSegDistance = cornerstoneTools.import('util/lineSegDistance')
const triggerEvent = cornerstoneTools.import('util/triggerEvent')
const moveNewHandle = cornerstoneTools.import('manipulators/moveNewHandle')

const addToolState = cornerstoneTools.addToolState
const getToolState = cornerstoneTools.getToolState
const removeToolState = cornerstoneTools.removeToolState

// Drawing
const drawLinkedTextBox = cornerstoneTools.import('drawing/drawLinkedTextBox')
const getNewContext = cornerstoneTools.import('drawing/getNewContext')
const draw = cornerstoneTools.import('drawing/draw')
// import textBoxWidth from './textBoxWidth'
const setShadow = cornerstoneTools.import('drawing/setShadow')
const drawArrow = cornerstoneTools.import('drawing/drawArrow')
const drawHandles = cornerstoneTools.import('drawing/drawHandles')
const { arrowAnnotateCursor } = cornerstoneTools.import('tools/cursors')
const getModule = cornerstoneTools.getModule

/**
 * @public
 * @class ArrowAnnotateTool
 * @memberof Tools.Annotation
 * @classdesc Create and position an arrow and label
 * @extends Tools.Base.BaseAnnotationTool
 */
export default class ArrowAnnotateTool extends cornerstoneTools.ArrowAnnotateTool {
  constructor(props = {}) {
    const defaultProps = {
      name: 'ArrowAnnotate',
      supportedInteractionTypes: ['Mouse', 'Touch'],
      configuration: {
        getTextCallback,
        changeTextCallback,
        drawHandles: false,
        drawHandlesOnHover: true,
        hideHandlesIfMoving: false,
        arrowFirst: true,
        renderDashed: false,
        allowEmptyLabel: false
      },
      svgCursor: arrowAnnotateCursor
    }

    super(props, defaultProps)
    this.preventNewMeasurement = false
  }
  textBoxWidth(context, text, padding) {
    const font = textStyle.getFont()
    const origFont = context.font

    if (font && font !== origFont) {
      context.font = font
    }
    const width = context.measureText(text).width

    if (font && font !== origFont) {
      context.font = origFont
    }

    return width + 2 * padding
  }

  createNewMeasurement(evt) {
    // Create the measurement data for this tool with the end handle activated
    return {
      visible: true,
      active: true,
      color: undefined,
      text: '',
      handles: {
        start: {
          x: evt.detail.currentPoints.image.x,
          y: evt.detail.currentPoints.image.y,
          highlight: true,
          active: false
        },
        end: {
          x: evt.detail.currentPoints.image.x,
          y: evt.detail.currentPoints.image.y,
          highlight: true,
          active: false
        },
        textBox: {
          active: false,
          hasMoved: false,
          movesIndependently: false,
          drawnIndependently: true,
          allowedOutsideImage: true,
          hasBoundingBox: true
        }
      }
    }
  }

  pointNearTool(element, data, coords) {
    if (data.visible === false) {
      return false
    }

    return (
      lineSegDistance(element, data.handles.start, data.handles.end, coords) <
      25
    )
  }

  updateCachedStats() {
    // Implementing to satisfy BaseAnnotationTool
  }

  renderToolData(evt) {
    const { element, enabledElement } = evt.detail
    const {
      handleRadius,
      drawHandlesOnHover,
      hideHandlesIfMoving,
      renderDashed
    } = this.configuration

    // If we have no toolData for this element, return immediately as there is nothing to do
    const toolData = getToolState(element, this.name)

    if (!toolData) {
      return
    }

    // We have tool data for this element - iterate over each one and draw it
    const canvas = evt.detail.canvasContext.canvas
    const context = getNewContext(canvas)

    const lineWidth = toolStyle.getToolWidth()

    let lineDash

    if (renderDashed) {
      lineDash = getModule('globalConfiguration').configuration.lineDash
    }

    for (let i = 0; i < toolData.data.length; i++) {
      const data = toolData.data[i]

      if (data.visible === false) {
        continue
      }

      draw(context, context => {
        setShadow(context, this.configuration)

        const color = toolColors.getColorIfActive(data)

        // Draw the arrow
        const handleStartCanvas = external.cornerstone.pixelToCanvas(
          element,
          data.handles.start
        )
        const handleEndCanvas = external.cornerstone.pixelToCanvas(
          element,
          data.handles.end
        )

        // Config.arrowFirst = false;
        if (this.configuration.arrowFirst) {
          drawArrow(
            context,
            handleEndCanvas,
            handleStartCanvas,
            color,
            lineWidth,
            lineDash
          )
        } else {
          drawArrow(
            context,
            handleStartCanvas,
            handleEndCanvas,
            color,
            lineWidth,
            lineDash
          )
        }

        const handleOptions = {
          color,
          handleRadius,
          drawHandlesIfActive: drawHandlesOnHover,
          hideHandlesIfMoving
        }
        if (this.configuration.drawHandles) {
          drawHandles(context, evt.detail, data.handles, handleOptions)
        }
        const text = []

        if (data.hasOwnProperty('remark')) {
          if (data.hasOwnProperty('status') && data.status) {
            text.push(`${data.remark}(${data.status})`)
          } else {
            text.push(data.remark)
          }
        }

        text.push(textBoxText(data))

        // Draw the text
        if (text && text !== '') {
          // Calculate the text coordinates.
          const padding = 5
          const textWidth = this.textBoxWidth(context, text, padding)
          const textHeight = textStyle.getFontSize() + 10

          let distance = Math.max(textWidth, textHeight) / 2 + 5

          if (handleEndCanvas.x < handleStartCanvas.x) {
            distance = -distance
          }

          if (!data.handles.textBox.hasMoved) {
            let textCoords

            if (this.configuration.arrowFirst) {
              textCoords = {
                x: handleEndCanvas.x - textWidth / 2 + distance,
                y: handleEndCanvas.y - textHeight / 2
              }
            } else {
              // If the arrow is at the End position, the text should
              // Be placed near the Start position
              textCoords = {
                x: handleStartCanvas.x - textWidth / 2 - distance,
                y: handleStartCanvas.y - textHeight / 2
              }
            }

            const transform = external.cornerstone.internal.getTransform(
              enabledElement
            )

            transform.invert()

            const coords = transform.transformPoint(textCoords.x, textCoords.y)

            data.handles.textBox.x = coords.x
            data.handles.textBox.y = coords.y
          }

          drawLinkedTextBox(
            context,
            element,
            data.handles.textBox,
            text,
            data.handles,
            textBoxAnchorPoints,
            color,
            lineWidth,
            0,
            false
          )
        }
      })
    }

    function textBoxText(data) {
      return data.text
    }

    function textBoxAnchorPoints(handles) {
      const midpoint = {
        x: (handles.start.x + handles.end.x) / 2,
        y: (handles.start.y + handles.end.y) / 2
      }

      return [handles.start, midpoint, handles.end]
    }
  }

  addNewMeasurement(evt, interactionType) {
    const element = evt.detail.element
    const measurementData = this.createNewMeasurement(evt)

    const { allowEmptyLabel } = this.configuration

    // Associate this data with this imageId so we can render it and manipulate it
    addToolState(element, this.name, measurementData)
    external.cornerstone.updateImage(element)

    moveNewHandle(
      evt.detail,
      this.name,
      measurementData,
      measurementData.handles.end,
      this.options,
      interactionType,
      success => {
        if (success) {
          if (!allowEmptyLabel && measurementData.text === undefined) {
            this.configuration.getTextCallback(text => {
              if (text || allowEmptyLabel) {
                measurementData.text = text
                measurementData.active = false

                const modifiedEventData = {
                  toolName: this.name,
                  toolType: this.name, // Deprecation notice: toolType will be replaced by toolName
                  element,
                  measurementData
                }

                external.cornerstone.updateImage(element)
                triggerEvent(
                  element,
                  EVENTS.MEASUREMENT_COMPLETED,
                  modifiedEventData
                )
              } else {
                removeToolState(element, this.name, measurementData)
              }
            }, evt.detail)
          }
        } else {
          removeToolState(element, this.name, measurementData)
        }
        triggerEvent(element, EVENTS.MEASUREMENT_COMPLETED, {
          toolName: this.name,
          toolType: this.name, // Deprecation notice: toolType will be replaced by toolName
          element,
          measurementData
        })
        external.cornerstone.updateImage(element)
      }
    )
  }

  doubleClickCallback(evt) {
    return this._updateTextForNearbyAnnotation(evt)
  }

  touchPressCallback(evt) {
    return this._updateTextForNearbyAnnotation(evt)
  }

  _updateTextForNearbyAnnotation(evt) {
    const element = evt.detail.element
    const coords = evt.detail.currentPoints.canvas
    const toolState = getToolState(element, this.name)

    if (!toolState) {
      return false
    }

    for (let i = 0; i < toolState.data.length; i++) {
      const data = toolState.data[i]

      if (
        this.pointNearTool(element, data, coords) ||
        pointInsideBoundingBox(data.handles.textBox, coords)
      ) {
        data.active = true
        external.cornerstone.updateImage(element)

        // Allow relabelling via a callback
        this.configuration.changeTextCallback(
          data,
          evt.detail,
          this._doneChangingTextCallback.bind(this, element, data)
        )

        evt.stopImmediatePropagation()
        evt.preventDefault()
        evt.stopPropagation()

        return true
      }
    }
  }

  _doneChangingTextCallback(element, measurementData, updatedText, deleteTool) {
    if (deleteTool === true) {
      removeToolState(element, this.name, measurementData)
    } else {
      measurementData.text = updatedText
    }

    measurementData.active = false
    external.cornerstone.updateImage(element)

    triggerEvent(element, EVENTS.MEASUREMENT_MODIFIED, {
      toolName: this.name,
      toolType: this.name, // Deprecation notice: toolType will be replaced by toolName
      element,
      measurementData
    })
  }
}

function getTextCallback(doneChangingTextCallback) {
  doneChangingTextCallback(prompt('Enter your annotation:'))
}

function changeTextCallback(data, eventData, doneChangingTextCallback) {
  doneChangingTextCallback(prompt('Change your annotation:'))
}
