import { useContext, useState, useEffect } from 'react'
import {
  Typography,
  Spin,
  Flex,
  Space,
  Collapse,
  InputNumber,
  Descriptions,
  Button
} from 'antd'
import { LoadingOutlined, CaretLeftOutlined } from '@ant-design/icons'
import { PrintServerContext } from '../context/PrintServerContext'
import styled from 'styled-components'
import PropTypes from 'prop-types'
import BoolDisplay from './BoolDisplay'

const { Text } = Typography

const CustomCollapse = styled(Collapse)`
  .ant-collapse-header {
    padding: 0 !important;
  }
  .ant-collapse-content-box {
    padding-left: 0 !important;
    padding-right: 0 !important;
    padding-bottom: 0 !important;
  }
`

const PrinterPositionPanel = ({
  printerId,
  showControls = true,
  showMoreInfo = true,
  shouldUnsubscribe = true
}) => {
  const [positionData, setPositionData] = useState({
    speed_factor: 1.0, // eslint-disable-line
    speed: 100,
    extrude_factor: 1.0, // eslint-disable-line
    absolute_foordinates: true, // eslint-disable-line
    absolute_extrude: false, // eslint-disable-line
    homing_origin: [0.0, 0.0, 0.0, 0.0], // eslint-disable-line
    position: [0.0, 0.0, 0.0, 0.0],
    gcode_position: [0.0, 0.0, 0.0, 0.0] // eslint-disable-line
  })

  const [initialized, setInitialized] = useState(false)
  const { printServer } = useContext(PrintServerContext)
  const [speedFactor, setSpeedFactor] = useState(positionData.speed_factor)
  const [extrudeFactor, setExtrudeFactor] = useState(
    positionData.extrude_factor
  )

  useEffect(() => {
    const params = {
      printerId,
      objects: {
        toolhead: null,
        gcode_move: null // eslint-disable-line
      }
    }

    const notifyPositionStatusUpdate = (statusUpdate) => {
      if (statusUpdate?.toolhead) {
        setPositionData((prevData) => ({
          ...prevData,
          ...statusUpdate.toolhead
        }))
      }
      if (statusUpdate?.gcode_move) {
        setPositionData((prevData) => ({
          ...prevData,
          ...statusUpdate.gcode_move
        }))
      }
    }

    if (!initialized && printServer?.connected) {
      setInitialized(true)

      printServer.on('connect', () => {
        printServer.emit('printer.objects.subscribe', params)
        printServer.emit('printer.objects.query', params)
      })

      printServer.emit('printer.objects.subscribe', params)
      printServer.emit('printer.objects.query', params)
      printServer.on('notify_status_update', notifyPositionStatusUpdate)
    }

    setSpeedFactor(positionData.speed_factor)
    setExtrudeFactor(positionData.extrude_factor)

    return () => {
      if (printServer?.connected && initialized && shouldUnsubscribe) {
        printServer.off('notify_status_update', notifyPositionStatusUpdate)
        printServer.emit('printer.objects.unsubscribe', params)
      }
    }
  }, [printServer, initialized, printerId, shouldUnsubscribe])

  const handleSetSpeedFactor = () => {
    if (printServer) {
      printServer.emit('printer.gcode.script', {
        printerId,
        script: `M220 S${speedFactor * 100}`
      })
    }
  }

  const handleSetExtrudeFactor = () => {
    if (printServer) {
      printServer.emit('printer.gcode.script', {
        printerId,
        script: `M221 S${extrudeFactor * 100}`
      })
    }
  }

  const moreInfoItems = [
    {
      key: '1',
      label: 'More Position Data',
      children: (
        <>
          <Flex vertical gap={'middle'}>
            <Text>GCode Position:</Text>
            <Descriptions column={1} size='small' bordered>
              <Descriptions.Item label='X'>
                {positionData.gcode_position[0].toFixed(2)}mm
              </Descriptions.Item>
              <Descriptions.Item label='Y'>
                {positionData.gcode_position[1].toFixed(2)}mm
              </Descriptions.Item>
              <Descriptions.Item label='Z'>
                {positionData.gcode_position[2].toFixed(2)}mm
              </Descriptions.Item>
              <Descriptions.Item label='E'>
                {positionData.gcode_position[3].toFixed(2)}mm
              </Descriptions.Item>
            </Descriptions>
            <Text>Homing Origin:</Text>
            <Descriptions
              column={1}
              size='small'
              bordered
              style={{ flexGrow: 1 }}
            >
              <Descriptions.Item label='X' span={1}>
                {positionData.homing_origin[0].toFixed(2)}mm
              </Descriptions.Item>
              <Descriptions.Item label='Y' span={1}>
                {positionData.homing_origin[1].toFixed(2)}mm
              </Descriptions.Item>
              <Descriptions.Item label='Z' span={1}>
                {positionData.homing_origin[2].toFixed(2)}mm
              </Descriptions.Item>
              <Descriptions.Item label='E'>
                {positionData.homing_origin[3].toFixed(2)}mm
              </Descriptions.Item>
            </Descriptions>
          </Flex>
        </>
      )
    }
  ]

  return (
    <div style={{ minWidth: 190 }}>
      {positionData ? (
        <Flex vertical gap='middle'>
          <Flex vertical gap={'middle'}>
            <Descriptions column={1} size='small' bordered>
              <Descriptions.Item label='X'>
                {positionData.position[0].toFixed(2)}mm
              </Descriptions.Item>
              <Descriptions.Item label='Y'>
                {positionData.position[1].toFixed(2)}mm
              </Descriptions.Item>
              <Descriptions.Item label='Z'>
                {positionData.position[2].toFixed(2)}mm
              </Descriptions.Item>
              <Descriptions.Item label='E'>
                {positionData.position[3].toFixed(2)}mm
              </Descriptions.Item>
            </Descriptions>
            {showControls && (
              <>
                <Space direction='vertical' style={{ width: '100%' }}>
                  <Space direction='horizontal'>
                    <Text>Speed Factor:</Text>
                    <Space.Compact block size='small'>
                      <InputNumber
                        value={speedFactor.toFixed(2)}
                        min={0.1}
                        max={2}
                        step={0.1}
                        style={{ width: '100px' }}
                        onChange={(value) => setSpeedFactor(value)}
                        onPressEnter={handleSetSpeedFactor}
                        size='small'
                      />
                      <Button
                        type='default'
                        style={{ width: 40 }}
                        onClick={handleSetSpeedFactor}
                      >
                        Set
                      </Button>
                    </Space.Compact>
                  </Space>

                  <Space direction='horizontal'>
                    <Text>Extrude Factor:</Text>
                    <Space.Compact block size='small'>
                      <InputNumber
                        value={extrudeFactor.toFixed(2)}
                        min={0.1}
                        max={2}
                        step={0.1}
                        style={{ width: '100px' }}
                        onChange={(value) => setExtrudeFactor(value)}
                        onPressEnter={handleSetExtrudeFactor}
                        size='small'
                      />
                      <Button
                        type='default'
                        style={{ width: 40 }}
                        onClick={handleSetExtrudeFactor}
                      >
                        Set
                      </Button>
                    </Space.Compact>
                  </Space>
                </Space>
              </>
            )}
            <Descriptions column={1} size='small' bordered>
              <Descriptions.Item label='Current Speed'>
                {positionData.speed.toFixed(2)}mm/s
              </Descriptions.Item>
              <Descriptions.Item label='Absolute Coordinates'>
                {positionData ? (
                  <BoolDisplay
                    value={positionData.absolute_coordinates}
                    yesNo={true}
                  />
                ) : (
                  <Text>n/a</Text>
                )}
              </Descriptions.Item>
            </Descriptions>
          </Flex>

          {showMoreInfo && (
            <CustomCollapse
              ghost
              size='small'
              items={moreInfoItems}
              expandIcon={({ isActive }) => (
                <CaretLeftOutlined rotate={isActive ? 90 : 0} />
              )}
            />
          )}
        </Flex>
      ) : (
        <Flex justify='centre'>
          <Spin indicator={<LoadingOutlined spin />} size='large' />
        </Flex>
      )}
    </div>
  )
}

PrinterPositionPanel.propTypes = {
  printerId: PropTypes.string.isRequired,
  showControls: PropTypes.bool,
  showMoreInfo: PropTypes.bool,
  shouldUnsubscribe: PropTypes.bool
}

export default PrinterPositionPanel
