import React, { useEffect, useRef, useState } from 'react'
import { useSelector } from '@xstate/react'
import { interpolationIconDataUri } from '@itk-viewer/icons'
import ColorMapIconSelector from './ColorMapIconSelector'
import WindowLevelReset from './WindowLevelReset'
import '../style.css'
import Button from 'react-bootstrap/Button'
import Form from 'react-bootstrap/Form'
import Image from 'react-bootstrap/Image'
import OverlayTrigger from 'react-bootstrap/OverlayTrigger'
import Tooltip from 'react-bootstrap/Tooltip'
import cn from 'classnames'
import getSelectedImageContext from './getSelectedImageContext'

function ColorRangeInput(props) {
  const { service } = props
  const colorRangeInput = useRef(null)
  const interpolationButton = useRef(null)
  const [input1Tooltip, setInput1Tooltip] = useState('Color range min')
  const [input2Tooltip, setInput2Tooltip] = useState('Color range max')
  const send = service.send
  const name = useSelector(
    service,
    (state) => state.context.images.selectedName
  )
  const interpolationEnabled = useSelector(
    service,
    (state) =>
      state.context.images.actorContext.get(state.context.images.selectedName)
        .interpolationEnabled
  )

  const colorRanges = useSelector(
    service,
    (state) =>
      state.context.images.actorContext.get(state.context.images.selectedName)
        .colorRanges
  )

  const colorRangeBounds = useSelector(
    service,
    (state) =>
      state.context.images.actorContext.get(state.context.images.selectedName)
        .colorRangeBounds
  )

  const selectedComponent = useSelector(
    service,
    (state) =>
      state.context.images.actorContext.get(state.context.images.selectedName)
        .selectedComponent
  )

  const windowLevelEnabled = useSelector(
    service,
    (state) =>
      state.context.images.actorContext.get(state.context.images.selectedName)
        .windowLevelEnabled
  )

  const colorRangesSelected = useSelector(service, (state) =>
    state.context.images.actorContext
      .get(state.context.images.selectedName)
      .colorRanges.get(selectedComponent)
  )

  const boundsSelected = useSelector(service, (state) =>
    state.context.images.actorContext
      .get(state.context.images.selectedName)
      .colorRangeBounds.get(selectedComponent)
  )

  const actorContext = useSelector(service, (state) =>
    getSelectedImageContext(state)
  )

  const imageType = actorContext.image?.imageType.componentType

  useEffect(() => {
    service.machine.context.images.colorRangeInputRow = colorRangeInput.current
  }, [service.machine.context.images])

  useEffect(() => {
    setInput1Tooltip(windowLevelEnabled ? 'Window width' : 'Color range min')
    setInput2Tooltip(windowLevelEnabled ? 'Window level' : 'Color range max')
  }, [windowLevelEnabled])

  const toggleInterpolate = () => {
    send({
      type: 'TOGGLE_IMAGE_INTERPOLATION',
      data: name
    })
  }

  const currentRange =
    colorRanges.size && colorRangesSelected ? colorRangesSelected : [0, 1]
  const currentRangeMin = currentRange[0]
  const currentRangeMax = currentRange[1]

  const currentWidth = currentRange[1] - currentRange[0]
  const currentLevel = (currentRange[1] + currentRange[0]) / 2

  const currentBounds = colorRangeBounds.size ? boundsSelected : [0, 1]

  let [rangeMin, rangeMax] = [0, 0]

  if (
    actorContext.componentVisibilities.length === 1 &&
    actorContext.selectedComponent
  ) {
    ;[rangeMin, rangeMax] =
      actorContext.image.scaleInfo[actorContext.loadedScale].ranges[
        actorContext.selectedComponent
      ]
  } else if (
    actorContext.componentVisibilities.length > 1 &&
    actorContext.colorRangeBounds.get(actorContext.selectedComponent)
  ) {
    ;[rangeMin, rangeMax] = actorContext.colorRangeBounds.get(
      actorContext.selectedComponent
    )
  }
  const rangeStep =
    imageType?.slice(0, 5) === 'float' ? (rangeMax - rangeMin) / 200 : 1
  const windowingStep =
    10 ** Math.ceil(Math.log((currentBounds[1] - currentBounds[0]) / 1000))

  const [in1, setIn1] = useState('')
  const [in2, setIn2] = useState('')

  // update input box after machine changes
  useEffect(() => {
    if (!windowLevelEnabled) setIn1(currentRangeMin)
  }, [currentRangeMin, windowLevelEnabled])
  useEffect(() => {
    if (!windowLevelEnabled) setIn2(currentRangeMax)
  }, [currentRangeMax, windowLevelEnabled])

  useEffect(() => {
    if (windowLevelEnabled) setIn1(currentWidth)
  }, [currentWidth, windowLevelEnabled])
  useEffect(() => {
    if (windowLevelEnabled) setIn2(currentLevel)
  }, [currentLevel, windowLevelEnabled])

  const isValidBounds = (input1, input2) => {
    if (isNaN(input1) || isNaN(input2)) {
      return false
    }
    if (windowLevelEnabled) {
      return input1 > 0
    }
    return input1 < input2
  }

  const inputChanged = (input1, input2) => {
    let rangeMin
    let rangeMax
    if (windowLevelEnabled) {
      rangeMin = input2 - input1 / 2
      rangeMax = input2 + input1 / 2
    } else {
      const bounds = boundsSelected
      rangeMax = input2 >= bounds[1] ? bounds[1] : input2
      rangeMin = input1 <= bounds[0] ? bounds[0] : input1
    }
    send({
      type: 'IMAGE_COLOR_RANGE_CHANGED',
      data: {
        name,
        component: selectedComponent,
        range: [rangeMin, rangeMax]
      }
    })
  }

  const input1Changed = (val) => {
    setIn1(val)
    let input1 = parseFloat(val)
    let input2 = windowLevelEnabled ? currentLevel : currentRangeMax
    if (isValidBounds(input1, input2)) {
      inputChanged(input1, input2)
    }
  }

  const input2Changed = (val) => {
    setIn2(val)
    let input1 = windowLevelEnabled ? currentWidth : currentRangeMin
    let input2 = parseFloat(val)
    if (isValidBounds(input1, input2)) {
      inputChanged(input1, input2)
    }
  }

  const invalidNumber = !isValidBounds(in1, in2)

  return (
    colorRanges.size !== 0 && (
      <div
        ref={colorRangeInput}
        className="uiRow"
        style={{ background: 'rgba(127, 127, 127, 0.5)' }}
      >
        <OverlayTrigger
          transition={false}
          overlay={<Tooltip>Interpolation</Tooltip>}
        >
          <Button
            className={cn('icon-button', {
              checked: interpolationEnabled
            })}
            onClick={() => {
              toggleInterpolate()
            }}
            variant="secondary"
            ref={interpolationButton}
          >
            <Image src={interpolationIconDataUri}></Image>
          </Button>
        </OverlayTrigger>
        <OverlayTrigger
          transition={false}
          overlay={<Tooltip>{input1Tooltip}</Tooltip>}
        >
          <Form.Control
            className={cn('numberInput', {
              invalidNumber
            })}
            type="number"
            value={in1}
            onChange={(e) => {
              input1Changed(e.target.value)
            }}
            step={windowLevelEnabled ? windowingStep : rangeStep}
          />
        </OverlayTrigger>
        <ColorMapIconSelector {...props} />
        <OverlayTrigger
          transition={false}
          overlay={<Tooltip>{input2Tooltip}</Tooltip>}
        >
          <Form.Control
            className={cn('numberInput', {
              invalidNumber
            })}
            type="number"
            value={in2}
            onChange={(e) => {
              input2Changed(e.target.value)
            }}
            step={windowLevelEnabled ? windowingStep : rangeStep}
          />
        </OverlayTrigger>
        <WindowLevelReset {...props} />
      </div>
    )
  )
}

export default ColorRangeInput
