import * as cornerstoneTools from 'cornerstone-tools'
const external = cornerstoneTools.external

// State
const getToolState = cornerstoneTools.getToolState
const toolStyle = cornerstoneTools.toolStyle
const toolColors = cornerstoneTools.toolColors
const getModule = cornerstoneTools.getModule

// Drawing
const getNewContext = cornerstoneTools.import('drawing/getNewContext')
const draw = cornerstoneTools.import('drawing/draw')
const setShadow = cornerstoneTools.import('drawing/setShadow')
const drawCircle = cornerstoneTools.import('drawing/drawCircle')
const drawHandles = cornerstoneTools.import('drawing/drawHandles')
const drawLinkedTextBox = cornerstoneTools.import('drawing/drawLinkedTextBox')

// Util
// const calculateSUV = cornerstoneTools.import('util/calculateSUV')

const throttle = cornerstoneTools.import('util/throttle')
const getPixelSpacing = cornerstoneTools.import('util/getPixelSpacing')

const circleRoiCursor = cornerstoneTools.import('tools/cursors')
const getROITextBoxCoords = cornerstoneTools.import('util/getROITextBoxCoords')
import getCircleCoords from './getCircleCoords'
// const getCircleCoords = cornerstoneTools.import('util/getCircleCoords')
const numbersWithCommas = cornerstoneTools.import('util/numbersWithCommas')

// import calculateSUV from './../../util/calculateSUV.js'
// import { calculateEllipseStatistics } from './../../util/ellipse/index.js'
// import getROITextBoxCoords from '../../util/getROITextBoxCoords.js'
// import numbersWithCommas from './../../util/numbersWithCommas.js'
// import throttle from './../../util/throttle.js'
// import { getLogger } from '../../util/logger.js'
// import getPixelSpacing from '../../util/getPixelSpacing'

// import { circleRoiCursor } from '../cursors/index.js'
// import getCircleCoords from '../../util/getCircleCoords'

// const logger = getLogger('tools:annotation:CircleRoiTool')

/**
 * @public
 * @class CircleRoiTool
 * @memberof Tools.Annotation
 * @classdesc Tool for drawing circular regions of interest, and measuring
 * the statistics of the enclosed pixels.
 * @extends Tools.Base.BaseAnnotationTool
 */
export default class CircleRoiTool extends cornerstoneTools.CircleRoiTool {
  constructor(props = {}) {
    const defaultProps = {
      name: 'CircleRoi',
      supportedInteractionTypes: ['Mouse', 'Touch'],
      svgCursor: circleRoiCursor,
      configuration: {
        centerPointRadius: 0,
        renderDashed: false,
        hideHandlesIfMoving: false,
        digits: 1,
        showRadius: false,
        showPerimeter: false
      }
    }

    super(props, defaultProps)
    console.log(props.configuration)
    // this.digits = isNaN(parseInt(props.configuration.digits)) ? 2 : props.configuration.digits
    // console.log(this.digits)
    this.throttledUpdateCachedStats = throttle(this.updateCachedStats, 110)
  }

  renderToolData(evt) {
    const toolData = getToolState(evt.currentTarget, this.name)

    if (!toolData) {
      return
    }

    const getDistance = external.cornerstoneMath.point.distance
    const eventData = evt.detail
    const { image, element, canvasContext } = eventData
    const lineWidth = toolStyle.getToolWidth()
    const {
      handleRadius,
      drawHandlesOnHover,
      hideHandlesIfMoving,
      renderDashed,
      centerPointRadius
    } = this.configuration
    const newContext = getNewContext(canvasContext.canvas)
    const { rowPixelSpacing, colPixelSpacing } = getPixelSpacing(image)
    const lineDash = getModule('globalConfiguration').configuration.lineDash

    // Meta
    const seriesModule =
      external.cornerstone.metaData.get('generalSeriesModule', image.imageId) ||
      {}

    // Pixel Spacing
    const modality = seriesModule.modality
    const hasPixelSpacing = rowPixelSpacing && colPixelSpacing

    draw(newContext, context => {
      // If we have tool data for this element, iterate over each set and draw it
      for (let i = 0; i < toolData.data.length; i++) {
        const data = toolData.data[i]

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

        // Configure
        const color = toolColors.getColorIfActive(data)
        const handleOptions = {
          color,
          handleRadius,
          drawHandlesIfActive: drawHandlesOnHover,
          hideHandlesIfMoving
        }

        setShadow(context, this.configuration)

        const startCanvas = external.cornerstone.pixelToCanvas(
          element,
          data.handles.start
        )

        const endCanvas = external.cornerstone.pixelToCanvas(
          element,
          data.handles.end
        )

        // Calculating the radius where startCanvas is the center of the circle to be drawn
        const radius = getDistance(startCanvas, endCanvas)

        const circleOptions = { color }

        if (renderDashed) {
          circleOptions.lineDash = lineDash
        }

        // Draw Circle
        drawCircle(
          context,
          element,
          data.handles.start,
          radius,
          circleOptions,
          'pixel'
        )

        if (centerPointRadius && radius > 3 * centerPointRadius) {
          drawCircle(
            context,
            element,
            data.handles.start,
            centerPointRadius,
            circleOptions,
            'pixel'
          )
        }

        if (data.handles) {
          data.handles.start.drawnIndependently = true
          data.handles.end.drawnIndependently = true
        }

        drawHandles(context, eventData, data.handles, handleOptions)

        // Update textbox stats
        if (data.invalidated === true) {
          if (data.cachedStats) {
            this.throttledUpdateCachedStats(image, element, data)
          } else {
            this.updateCachedStats(image, element, data)
          }
        }

        // Default to textbox on right side of ROI
        if (!data.handles.textBox.hasMoved) {
          const defaultCoords = getROITextBoxCoords(
            eventData.viewport,
            data.handles
          )

          Object.assign(data.handles.textBox, defaultCoords)
        }

        const textBoxAnchorPoints = handles =>
          _findTextBoxAnchorPoints(handles.start, handles.end)

        const textBoxContent = _createTextBoxContent(
          context,
          image.color,
          data.cachedStats,
          modality,
          hasPixelSpacing,
          this.configuration
        )
        if (data.remark) {
          textBoxContent.unshift(data.remark)
        }
        data.unit = _getUnit(modality, this.configuration.showHounsfieldUnits)

        drawLinkedTextBox(
          context,
          element,
          data.handles.textBox,
          textBoxContent,
          data.handles,
          textBoxAnchorPoints,
          color,
          lineWidth,
          20,
          true
        )
      }
    })
  }
}

/**
 *
 *
 * @param {*} startHandle
 * @param {*} endHandle
 * @returns {Array.<{x: number, y: number}>}
 */
function _findTextBoxAnchorPoints(startHandle, endHandle) {
  const { left, top, width, height } = getCircleCoords(startHandle, endHandle)

  return [
    {
      // Top middle point of ellipse
      x: left + width / 2,
      y: top
    },
    {
      // Left middle point of ellipse
      x: left,
      y: top + height / 2
    },
    {
      // Bottom middle point of ellipse
      x: left + width / 2,
      y: top + height
    },
    {
      // Right middle point of ellipse
      x: left + width,
      y: top + height / 2
    }
  ]
}

function _getUnit(modality, showHounsfieldUnits) {
  return modality === 'CT' && showHounsfieldUnits !== false ? 'HU' : ''
}

/**
 *
 *
 * @param {*} context
 * @param {*} isColorImage
 * @param {*} { area, mean, stdDev, min, max, meanStdDevSUV }
 * @param {*} modality
 * @param {*} hasPixelSpacing
 * @param {*} [options={}] - { showMinMax, showHounsfieldUnits }
 * @returns {string[]}
 */
function _createTextBoxContent(
  context,
  isColorImage,
  {
    area = 0,
    radius = 0,
    perimeter = 0,
    mean = 0,
    stdDev = 0,
    min = 0,
    max = 0,
    meanStdDevSUV = 0
  } = {},
  modality,
  hasPixelSpacing,
  options = {}
) {
  const showMinMax = options.showMinMax || false
  const digits = options.digits || 1
  const textLines = []

  // Don't display mean/standardDev for color images
  const otherLines = []

  if (!isColorImage) {
    const hasStandardUptakeValues = meanStdDevSUV && meanStdDevSUV.mean !== 0
    const unit = _getUnit(modality, options.showHounsfieldUnits)

    let meanString = `Mean: ${numbersWithCommas(mean.toFixed(digits))} ${unit}`
    const stdDevString = `Std Dev: ${numbersWithCommas(
      stdDev.toFixed(digits)
    )} ${unit}`

    // If this image has SUV values to display, concatenate them to the text line
    if (hasStandardUptakeValues) {
      const SUVtext = ' SUV: '

      const meanSuvString = `${SUVtext}${numbersWithCommas(
        meanStdDevSUV.mean.toFixed(digits)
      )}`
      const stdDevSuvString = `${SUVtext}${numbersWithCommas(
        meanStdDevSUV.stdDev.toFixed(digits)
      )}`

      const targetStringLength = Math.floor(
        context.measureText(`${stdDevString}     `).width
      )

      while (context.measureText(meanString).width < targetStringLength) {
        meanString += ' '
      }

      otherLines.push(`${meanString}${meanSuvString}`)
      otherLines.push(`${stdDevString}     ${stdDevSuvString}`)
    } else {
      // otherLines.push(`${meanString}     ${stdDevString}`)
      otherLines.push(`${meanString}`)
      otherLines.push(`${stdDevString}`)
    }

    if (showMinMax) {
      let minString = `Min: ${min} ${unit}`
      const maxString = `Max: ${max} ${unit}`
      const targetStringLength = hasStandardUptakeValues
        ? Math.floor(context.measureText(`${stdDevString}     `).width)
        : Math.floor(context.measureText(`${meanString}     `).width)

      while (context.measureText(minString).width < targetStringLength) {
        minString += ' '
      }
      otherLines.push(`${minString}`)
      otherLines.push(`${maxString}`)
      // otherLines.push(`${minString}${maxString}`)
    }
  }

  textLines.push(_formatArea(area, hasPixelSpacing, digits))
  const showRadius = options.showRadius || false
  if (radius && showRadius) {
    textLines.push(_formatLength(radius, 'Radius', hasPixelSpacing, digits))
  }
  const showPerimeter = options.showPerimeter || false
  if (perimeter && showPerimeter) {
    textLines.push(_formatLength(perimeter, 'Perimeter', hasPixelSpacing, digits))
  }
  otherLines.forEach(x => textLines.push(x))
  // console.log(this.digits)
  return textLines
}

/**
 *
 *
 * @param {*} area
 * @param {*} hasPixelSpacing
 * @returns {string} The formatted label for showing area
 */
function _formatArea(area, hasPixelSpacing, digits) {
  // This uses Char code 178 for a superscript 2
  const suffix = hasPixelSpacing
    ? ` mm${String.fromCharCode(178)}`
    : ` px${String.fromCharCode(178)}`

  return `Area: ${numbersWithCommas(area.toFixed(digits))}${suffix}`
}

function _formatLength(value, name, hasPixelSpacing, digits) {
  if (!value) {
    return ''
  }
  const suffix = hasPixelSpacing ? ' mm' : ' px'

  return `${name}: ${numbersWithCommas(value.toFixed(digits))}${suffix}`
}

/**
 *
 *
 * @param {*} image
 * @param {*} element
 * @param {*} handles
 * @param {*} modality
 * @param {*} pixelSpacing
 * @returns {Object} The Stats object
 */
// function _calculateStats(image, element, handles, modality, pixelSpacing) {
//   // Retrieve the bounds of the ellipse in image coordinates
//   const circleCoordinates = getCircleCoords(handles.start, handles.end)

//   // Retrieve the array of pixels that the ellipse bounds cover
//   const pixels = external.cornerstone.getPixels(
//     element,
//     circleCoordinates.left,
//     circleCoordinates.top,
//     circleCoordinates.width,
//     circleCoordinates.height
//   )

//   // Calculate the mean & standard deviation from the pixels and the ellipse details.
//   const ellipseMeanStdDev = calculateEllipseStatistics(
//     pixels,
//     circleCoordinates
//   )

//   let meanStdDevSUV

//   if (modality === 'PT') {
//     meanStdDevSUV = {
//       mean: calculateSUV(image, ellipseMeanStdDev.mean, true) || 0,
//       stdDev: calculateSUV(image, ellipseMeanStdDev.stdDev, true) || 0
//     }
//   }

//   const radius =
//     (circleCoordinates.width *
//       ((pixelSpacing && pixelSpacing.colPixelSpacing) || 1)) /
//     2
//   const perimeter = 2 * Math.PI * radius
//   const area =
//     Math.PI *
//     ((circleCoordinates.width *
//       ((pixelSpacing && pixelSpacing.colPixelSpacing) || 1)) /
//       2) *
//     ((circleCoordinates.height *
//       ((pixelSpacing && pixelSpacing.rowPixelSpacing) || 1)) /
//       2)

//   return {
//     area: area || 0,
//     radius: radius || 0,
//     perimeter: perimeter || 0,
//     count: ellipseMeanStdDev.count || 0,
//     mean: ellipseMeanStdDev.mean || 0,
//     variance: ellipseMeanStdDev.variance || 0,
//     stdDev: ellipseMeanStdDev.stdDev || 0,
//     min: ellipseMeanStdDev.min || 0,
//     max: ellipseMeanStdDev.max || 0,
//     meanStdDevSUV
//   }
// }
