import React, { useRef } from 'react'
import { useSelector } from '@xstate/react'
import {
  visibleIconDataUri,
  invisibleIconDataUri,
  pauseIconDataUri,
  playIconDataUri
} from '@itk-viewer/icons'
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 Badge from 'react-bootstrap/Badge'
import '../style.css'

const planes = ['x', 'y', 'z']
const PLANE_VIEW_MODES = ['XPlane', 'YPlane', 'ZPlane']

function PlaneSliders({ service }) {
  const { send } = service
  const xVisibility = useRef(null)
  const yVisibility = useRef(null)
  const zVisibility = useRef(null)
  const xScroll = useRef(null)
  const yScroll = useRef(null)
  const zScroll = useRef(null)
  const visRefs = [xVisibility, yVisibility, zVisibility]
  const scrollRefs = [xScroll, yScroll, zScroll]
  const slicingPlanes = useSelector(
    service,
    (state) => state.context.main.slicingPlanes
  )

  const hidden = useSelector(service, (state) => {
    // Changing view mode does not change slicingPlanes visible prop
    const planeModeOn = PLANE_VIEW_MODES.some((mode) => {
      return mode === state.context.main.viewMode
    })

    // slicingPlanes visible prop only changed on 3D "View Planes" button
    // This detects if 3D View Planes is on
    const { slicingPlanes } = state.context.main
    const isPlaneVisible =
      slicingPlanes.x.visible ||
      slicingPlanes.y.visible ||
      slicingPlanes.z.visible

    return state.context.uiCollapsed || (!planeModeOn && !isPlaneVisible)
  })
  const stateContextUse2D = useSelector(service, (state) => state.context.use2D)

  // Force re-render so sliders disappear in 2D mode
  const viewMode = useSelector(service, (state) => state.context.main.viewMode)

  // Force re-render for 2D view modes
  const planeSlice2D = planes.map((plane) =>
    useSelector(service, (state) => state.context.main[`${plane}Slice`])
  )

  // Force re-render for visibility button
  const slicingPlanesVisibility = planes.map((plane) =>
    useSelector(
      service,
      (state) => state.context.main.slicingPlanes[`${plane}`].visible
    )
  )

  // Force re-render for play/pause button
  const slicingPlanesScroll = useSelector(
    service,
    (state) =>
      planes.map(
        (plane) => state.context.main.slicingPlanes[`${plane}`].scroll
      ),
    (a, b) => a.length === b.length && a.every((x, i) => x === b[i])
  )

  const toggleVisibility = (plane) => {
    slicingPlanes[plane].visible = !slicingPlanes[plane].visible
    send({ type: 'SLICING_PLANES_CHANGED', data: slicingPlanes })
  }

  const togglePlay = (plane) => {
    slicingPlanes[plane].scroll = !slicingPlanes[plane].scroll
    if (slicingPlanes[plane].scroll && !slicingPlanes[plane].visible) {
      toggleVisibility(plane)
    }
    send({ type: 'SLICING_PLANES_CHANGED', data: slicingPlanes })
  }

  const handleSliderChange = (plane, val) => {
    send({
      type: `${plane.toUpperCase()}_SLICE_CHANGED`,
      data: Number(val)
    })
  }

  const sliderVisible = (plane) => {
    const isVolume = viewMode === 'Volume' && !stateContextUse2D
    const planeVisible = viewMode === `${plane.toUpperCase()}Plane`
    if (!isVolume && !planeVisible) {
      return 'hiddenSlider'
    }
    return ''
  }

  return (
    <div hidden={hidden}>
      {planes.map((plane, idx) => {
        return (
          planeSlice2D[idx] !== null &&
          !service.machine.context.use2D && (
            <div key={plane.toUpperCase()}>
              <div className="input-group">
                <OverlayTrigger
                  transition={false}
                  overlay={
                    <Tooltip>{plane.toUpperCase()} Plane Visibility</Tooltip>
                  }
                >
                  <Button
                    className={cn(
                      `icon-button ${
                        viewMode !== 'Volume' ? 'hiddenSlider' : ''
                      }`,
                      {
                        checked: slicingPlanesVisibility[idx]
                      }
                    )}
                    onClick={(_e) => {
                      toggleVisibility(plane)
                    }}
                    variant="secondary"
                    ref={visRefs[idx]}
                  >
                    {slicingPlanes[plane].visible ? (
                      <Image src={visibleIconDataUri}></Image>
                    ) : (
                      <Image src={invisibleIconDataUri}></Image>
                    )}
                  </Button>
                </OverlayTrigger>
                <OverlayTrigger
                  transition={false}
                  overlay={
                    <Tooltip>{`${plane.toUpperCase()} Plane Toggle Scroll`}</Tooltip>
                  }
                >
                  <Button
                    className={cn(
                      `icon-button ${
                        viewMode !== `${plane.toUpperCase()}Plane` &&
                        viewMode !== 'Volume'
                          ? 'hiddenSlider'
                          : ''
                      }`,
                      {
                        checked: slicingPlanesScroll[idx]
                      }
                    )}
                    onClick={(_e) => {
                      togglePlay(plane)
                    }}
                    variant="secondary"
                    ref={scrollRefs[idx]}
                  >
                    {slicingPlanes[plane].scroll ? (
                      <Image src={pauseIconDataUri}></Image>
                    ) : (
                      <Image src={playIconDataUri}></Image>
                    )}
                  </Button>
                </OverlayTrigger>
                <Badge
                  className={`labelBadge ${plane}badge ${
                    viewMode !== `${plane.toUpperCase()}Plane` &&
                    viewMode !== 'Volume'
                      ? 'hiddenSlider'
                      : ''
                  }`}
                  bg="secondary"
                >
                  {plane.toUpperCase()}: {planeSlice2D[idx]?.toPrecision(4)}
                </Badge>
                <div
                  key={plane.toUpperCase()}
                  className={`planeSliders ${sliderVisible(plane)}`}
                >
                  <Form.Control
                    type="range"
                    custom
                    min={slicingPlanes[plane].min}
                    max={slicingPlanes[plane].max}
                    value={planeSlice2D[idx]}
                    step={slicingPlanes[plane].step}
                    onChange={(_e) => {
                      handleSliderChange(plane, _e.target.value)
                    }}
                  />
                </div>
              </div>
            </div>
          )
        )
      })}
    </div>
  )
}

export default PlaneSliders
