import * as cornerstoneTools from 'cornerstone-tools'
import * as cornerstone from 'cornerstone-core'
import getCircleCoords from '../CircleRoi/getCircleCoords'
const EVENTS = cornerstoneTools.EVENTS
const getPixelSpacing = cornerstoneTools.importInternal('util/getPixelSpacing')
const triggerEvent = cornerstoneTools.import('util/triggerEvent')
const external = cornerstoneTools.external
const getToolState = cornerstoneTools.getToolState
const toolStyle = cornerstoneTools.toolStyle
const toolColors = cornerstoneTools.toolColors
const getModule = cornerstoneTools.getModule
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')
const getROITextBoxCoords = cornerstoneTools.import('util/getROITextBoxCoords')
const numbersWithCommas = cornerstoneTools.import('util/numbersWithCommas')

/**
 * @public
 * @class FixedCircleRoiTool
 * @memberof Tools.Annotation
 * @classdesc Tool for drawing circular regions of interest with a fixed radius, and measuring
 * the statistics of the enclosed pixels.
 * @extends Tools.Annotation.CircleRoiTool
 */
export default class FixedCircleRoiTool extends cornerstoneTools.CircleRoiTool {
  constructor(props = {}) {
    const defaultProps = {
      name: 'FixedCircleRoi',
      configuration: {
        radius: 10, // Default radius in units (mm by default)
        unit: 'mm', // 'mm' or 'px'
        centerPointRadius: 0,
        renderDashed: false,
        drawHandlesOnHover: false,
        handleRadius: 0,
        digits: 1,
      },
    };
    super(props, defaultProps);

    // Explicitly set name to ensure it is defined
    this.name = 'FixedCircleRoi';

    // Manually merge configuration to ensure props override defaults
    if (props && props.configuration) {
      this.configuration = Object.assign(
        {},
        this.configuration || defaultProps.configuration,
        props.configuration
      );
    }
  }

  createNewMeasurement(eventData) {
    const measurementData = super.createNewMeasurement(eventData);

    if (!measurementData) {
      return;
    }

    const { image } = eventData;
    // Fallback if configuration is missing
    if (!this.configuration) {
      console.warn(
        'FixedCircleRoiTool: configuration missing, using defaults'
      );
      this.configuration = { radius: 10, unit: 'mm' };
    }

    const config = this.configuration;
    let radiusPixels = config.radius;

    if (config.unit === 'mm') {
      const pixelSpacing = getPixelSpacing(image);
      console.log(
        'FixedCircleRoiTool: PixelSpacing retrieved:',
        pixelSpacing
      );

      const { colPixelSpacing } = pixelSpacing;

      if (colPixelSpacing && colPixelSpacing > 0) {
        radiusPixels = config.radius / colPixelSpacing;
      } else {
        console.warn(
          'FixedCircleRoiTool: Invalid pixel spacing, treating radius as pixels'
        );
      }
    }

    // Ensure radiusPixels is a valid number
    if (isNaN(radiusPixels)) {
      console.warn(
        'FixedCircleRoiTool: radiusPixels is NaN, defaulting to 10px'
      );
      radiusPixels = 10;
    }

    // Set end handle position based on calculated radius pixels
    measurementData.handles.end.x =
      measurementData.handles.start.x + radiusPixels;
    measurementData.handles.end.y = measurementData.handles.start.y;

    console.log(
      'FixedCircleRoiTool created measurement:',
      JSON.parse(JSON.stringify(measurementData))
    );

    // Invalidate to trigger stats calculation
    measurementData.invalidated = true;

    return measurementData;
  }

  /**
   * Overwrite the addNewMeasurement method to prevent the default behavior
   * of resizing the circle on mouse drag immediately after creation.
   */
  addNewMeasurement(evt, interactionType) {
    const eventData = evt.detail;
    if (
      !eventData ||
      !eventData.currentPoints ||
      !eventData.currentPoints.image
    ) {
      console.warn(
        'FixedCircleRoiTool: Invalid eventData supplied to addNewMeasurement'
      );
      return;
    }

    const element = eventData.element;

    // 1. Create the measurement data (which already has the fixed radius)
    const measurementData = this.createNewMeasurement(eventData);

    if (!measurementData) return;

    // 2. Add it to the tool state
    cornerstoneTools.addToolState(element, this.name, measurementData);

    // 3. Ensure stats are available for completion listeners (e.g. mean value consumers).
    if (!measurementData.cachedStats && eventData.image) {
      this.updateCachedStats(eventData.image, element, measurementData)
    }

    // 4. Update the image to show the new annotation
    cornerstone.updateImage(element);

    // 5. Manually emit completion event since we bypass default drag-finish flow.
    triggerEvent(element, EVENTS.MEASUREMENT_COMPLETED, {
      toolName: this.name,
      element,
      measurementData,
    })

    // 6. Do NOT attach mouse/touch event listeners for resizing.
    // The circle is created with fixed size and placed immediately.
  }

  handleSelectedCallback(evt, measurementData, handle, interactionType = 'mouse') {
    // Lock circle radius by preventing start/end handle drag.
    if (measurementData && measurementData.handles) {
      const { start, end } = measurementData.handles
      if (handle === start || handle === end) {
        evt.stopImmediatePropagation?.()
        evt.preventDefault?.()
        return
      }
    }

    super.handleSelectedCallback(evt, measurementData, handle, interactionType)
  }

  pointNearTool(element, data, coords, interactionType = 'mouse') {
    const isNearDefault = super.pointNearTool(element, data, coords, interactionType)
    if (isNearDefault) {
      return true
    }
    if (!data || !data.handles || !data.handles.start || !data.handles.end) {
      return false
    }

    const centerCanvas = external.cornerstone.pixelToCanvas(element, data.handles.start)
    const edgeCanvas = external.cornerstone.pixelToCanvas(element, data.handles.end)
    const radius = external.cornerstoneMath.point.distance(centerCanvas, edgeCanvas)
    const distanceToCenter = external.cornerstoneMath.point.distance(centerCanvas, coords)

    return distanceToCenter <= radius
  }

  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

    const seriesModule =
      external.cornerstone.metaData.get('generalSeriesModule', image.imageId) ||
      {}
    const modality = seriesModule.modality
    const hasPixelSpacing = rowPixelSpacing && colPixelSpacing

    draw(newContext, context => {
      for (let i = 0; i < toolData.data.length; i++) {
        const data = toolData.data[i]

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

        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
        )
        const radius = getDistance(startCanvas, endCanvas)

        const circleOptions = { color }
        if (renderDashed) {
          circleOptions.lineDash = lineDash
        }

        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)

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

        if (!data.handles.textBox.hasMoved) {
          const defaultCoords = getROITextBoxCoords(
            eventData.viewport,
            data.handles
          )
          Object.assign(data.handles.textBox, defaultCoords)
        }

        const textBoxContent = []
        console.log(data)
        if (data.remark) {
          textBoxContent.push(data.remark)
        }

        const digits = this.configuration.digits || 1
        if (!image.color && data.cachedStats && Number.isFinite(data.cachedStats.mean)) {
          const unit = modality === 'CT' && this.configuration.showHounsfieldUnits !== false ? 'HU' : ''
          const meanText = numbersWithCommas(data.cachedStats.mean.toFixed(digits))
          textBoxContent.push(unit ? `Mean: ${meanText} ${unit}` : `Mean: ${meanText}`)
        }

        if (!textBoxContent.length) {
          continue
        }

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

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

        data.unit = modality === 'CT' && this.configuration.showHounsfieldUnits !== false ? 'HU' : ''
      }
    })
  }
}

function findTextBoxAnchorPoints(startHandle, endHandle) {
  const { left, top, width, height } = getCircleCoords(startHandle, endHandle)

  return [
    { x: left + width / 2, y: top },
    { x: left, y: top + height / 2 },
    { x: left + width / 2, y: top + height },
    { x: left + width, y: top + height / 2 },
  ]
}
