import React from 'react'
import {
  Button,
  Col,
  Divider,
  InputNumber,
  Menu,
  Popover,
  Row,
  Select,
  Slider,
  Space,
  Switch
} from 'antd'
import { SettingOutlined } from '@ant-design/icons'
import { FaEye, FaEyeSlash } from 'react-icons/fa'
import * as dmv from 'dicom-microscopy-viewer'
import * as dcmjs from 'dcmjs'

import Description from './Description'

interface AnnotationGroupItemProps {
  annotationGroup: dmv.annotation.AnnotationGroup
  isVisible: boolean
  metadata: dmv.metadata.MicroscopyBulkSimpleAnnotations
  defaultStyle: {
    opacity: number
  }
  onVisibilityChange: ({ annotationGroupUID, isVisible }: {
    annotationGroupUID: string
    isVisible: boolean
  }) => void
  onStyleChange: ({ annotationGroupUID, styleOptions }: {
    annotationGroupUID: string
    styleOptions: {
      opacity?: number
      measurement?: dcmjs.sr.coding.CodedConcept
    }
  }) => void
}

interface AnnotationGroupItemState {
  isVisible: boolean
  currentStyle: {
    opacity: number
    measurement?: dcmjs.sr.coding.CodedConcept
  }
}

/**
 * React component representing an Annotation Group.
 */
class AnnotationGroupItem extends React.Component<AnnotationGroupItemProps, AnnotationGroupItemState> {
  constructor (props: AnnotationGroupItemProps) {
    super(props)
    this.handleVisibilityChange = this.handleVisibilityChange.bind(this)
    this.handleMeasurementSelection = this.handleMeasurementSelection.bind(this)
    this.handleOpacityChange = this.handleOpacityChange.bind(this)
    this.state = {
      isVisible: this.props.isVisible,
      currentStyle: { opacity: this.props.defaultStyle.opacity }
    }
  }

  handleVisibilityChange (
    checked: boolean,
    event: Event
  ): void {
    this.props.onVisibilityChange({
      annotationGroupUID: this.props.annotationGroup.uid,
      isVisible: checked
    })
  }

  handleOpacityChange (value: number): void {
    this.props.onStyleChange({
      annotationGroupUID: this.props.annotationGroup.uid,
      styleOptions: {
        opacity: value
      }
    })
    this.setState({ currentStyle: { opacity: value } })
  }

  handleMeasurementSelection (value?: string, option?: any): void {
    if (value !== undefined) {
      const codeComponents = value.split('-')
      const measurement = new dcmjs.sr.coding.CodedConcept({
        value: codeComponents[1],
        schemeDesignator: codeComponents[0],
        meaning: option.children
      })
      this.props.onStyleChange({
        annotationGroupUID: this.props.annotationGroup.uid,
        styleOptions: { measurement }
      })
      this.setState(state => ({
        currentStyle: {
          opacity: state.currentStyle.opacity,
          measurement
        }
      }))
    } else {
      this.setState(state => ({
        currentStyle: {
          opacity: state.currentStyle.opacity
        }
      }))
    }
  }

  render (): React.ReactNode {
    const identifier = `Annotation Group ${this.props.annotationGroup.number}`
    const attributes: Array<{ name: string, value: string }> = [
      {
        name: 'Label',
        value: this.props.annotationGroup.label
      },
      {
        name: 'Algorithm Name',
        value: this.props.annotationGroup.algorithmName
      },
      {
        name: 'Property category',
        value: this.props.annotationGroup.propertyCategory.CodeMeaning
      },
      {
        name: 'Property type',
        value: this.props.annotationGroup.propertyType.CodeMeaning
      }
    ]

    const index = this.props.metadata.AnnotationGroupSequence.findIndex(
      item => (item.AnnotationGroupUID === this.props.annotationGroup.uid)
    )
    const item = this.props.metadata.AnnotationGroupSequence[index]
    const measurementsSequence = item.MeasurementsSequence ?? []

    const measurementOptions = measurementsSequence.map(measurementItem => {
      const name = measurementItem.ConceptNameCodeSequence[0]
      const key = `${name.CodingSchemeDesignator}-${name.CodeValue}`
      return (
        <Select.Option
          key={key}
          value={key}
          dropdownMatchSelectWidth={false}
          size='small'
          disabled={!this.props.isVisible}
        >
          {name.CodeMeaning}
        </Select.Option>
      )
    })

    const settings = (
      <div>
        <Row justify='start' align='middle' gutter={[8, 8]}>
          <Col span={6}>
            Opacity
          </Col>
          <Col span={12}>
            <Slider
              range={false}
              min={0}
              max={1}
              step={0.01}
              value={this.state.currentStyle.opacity}
              onChange={this.handleOpacityChange}
            />
          </Col>
          <Col span={6}>
            <InputNumber
              min={0}
              max={1}
              size='small'
              step={0.1}
              style={{ width: '65px' }}
              value={this.state.currentStyle.opacity}
              onChange={this.handleOpacityChange}
            />
          </Col>
        </Row>
        <Divider plain>
          Exploration
        </Divider>
        <Row justify='start' align='middle' gutter={[8, 8]}>
          <Col span={8}>
            Measurement
          </Col>
          <Col span={16}>
            <Select
              style={{ minWidth: '65px', width: '90%' }}
              onSelect={this.handleMeasurementSelection}
              key='annotation-group-measurements'
              defaultValue={undefined}
            >
              {measurementOptions}
            </Select>
          </Col>
        </Row>
      </div>
    )

    const {
      annotationGroup,
      defaultStyle,
      isVisible,
      metadata,
      onVisibilityChange,
      onStyleChange,
      ...otherProps
    } = this.props
    return (
      <Menu.Item
        style={{ height: '100%', paddingLeft: '3px' }}
        key={this.props.annotationGroup.uid}
        {...otherProps}
      >
        <Space align='start'>
          <div style={{ paddingLeft: '14px' }}>
            <Space direction='vertical' align='end'>
              <Switch
                size='small'
                onChange={this.handleVisibilityChange}
                checked={this.props.isVisible}
                checkedChildren={<FaEye />}
                unCheckedChildren={<FaEyeSlash />}
              />
              <Popover
                placement='left'
                content={settings}
                overlayStyle={{ width: '350px' }}
                title='Display Settings'
              >
                <Button
                  type='primary'
                  shape='circle'
                  icon={<SettingOutlined />}
                />
              </Popover>
            </Space>
          </div>
          <Description
            header={identifier}
            attributes={attributes}
            selectable
            hasLongValues
          />
        </Space>
      </Menu.Item>
    )
  }
}

export default AnnotationGroupItem