import { useContext, useState, useEffect } from 'react'
import {
  Typography,
  Spin,
  Flex,
  Space,
  Collapse,
  InputNumber,
  Descriptions,
  Button,
  Divider
} from 'antd'
import { LoadingOutlined, CaretRightOutlined } from '@ant-design/icons'
import { ApiServerContext } from '../context/ApiServerContext'
import styled from 'styled-components'
import PropTypes from 'prop-types'
import BoolDisplay from './BoolDisplay'
import merge from 'lodash/merge'
import { round } from '../utils/Utils'
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 = ({
  id,
  showControls = true,
  showMoreInfo = true
}) => {
  const { subscribeToObjectEvent, connected, sendObjectAction } =
    useContext(ApiServerContext)
  const [positionData, setPositionData] = useState({
    speedFactor: 1.0, // eslint-disable-line
    speed: 100,
    extrudeFactor: 1.0, // eslint-disable-line
    absoluteCoordinates: true, // eslint-disable-line
    absoluteExtrude: false, // eslint-disable-line
    homingOrigin: [0.0, 0.0, 0.0, 0.0], // eslint-disable-line
    toolheadPosition: [0.0, 0.0, 0.0, 0.0],
    gcodePosition: [0.0, 0.0, 0.0, 0.0], // eslint-disable-line
    livePosition: [0.0, 0.0, 0.0, 0.0],
    maxVelocity: 1000,
    maxAcceleration: 1000,
    squareCornerVelocity: 100,
    minCruiseRatio: 0
  })

  useEffect(() => {
    if (id && connected == true) {
      const motionEventUnsubscribe = subscribeToObjectEvent(
        id,
        'printer',
        'motion',
        (event) => {
          setPositionData((prev) => {
            const merged = merge({}, prev, event.data)
            return merged
          })
        }
      )
      return () => {
        if (motionEventUnsubscribe) motionEventUnsubscribe()
      }
    }
  }, [id, connected])
  const [speedFactor, setSpeedFactor] = useState(positionData.speedFactor)
  const [extrudeFactor, setExtrudeFactor] = useState(positionData.extrudeFactor)
  const [maxVelocity, setMaxVelocity] = useState(positionData.maxVelocity)
  const [maxAcceleration, setMaxAcceleration] = useState(
    positionData.maxAcceleration
  )
  const [squareCornerVelocity, setSquareCornerVelocity] = useState(
    positionData.squareCornerVelocity
  )
  const [minCruiseRatio, setMinCruiseRatio] = useState(
    positionData.minCruiseRatio
  )

  useEffect(() => {
    if (positionData.speedFactor !== undefined) {
      setSpeedFactor(positionData.speedFactor)
    }
    if (positionData.extrudeFactor !== undefined) {
      setExtrudeFactor(positionData.extrudeFactor)
    }
    if (positionData.maxVelocity !== undefined) {
      setMaxVelocity(positionData.maxVelocity)
    }
    if (positionData.maxAcceleration !== undefined) {
      setMaxAcceleration(positionData.maxAcceleration)
    }
    if (positionData.squareCornerVelocity !== undefined) {
      setSquareCornerVelocity(positionData.squareCornerVelocity)
    }
    if (positionData.minCruiseRatio !== undefined) {
      setMinCruiseRatio(positionData.minCruiseRatio)
    }
  }, [
    positionData.speedFactor,
    positionData.extrudeFactor,
    positionData.maxVelocity,
    positionData.maxAcceleration,
    positionData.squareCornerVelocity,
    positionData.minCruiseRatio
  ])

  const handleSetSpeedFactor = () => {
    if (id && connected == true) {
      sendObjectAction(id, 'printer', {
        type: 'setSpeedFactor',
        data: {
          speedFactor: speedFactor * 100
        }
      })
    }
  }

  const handleSetExtrudeFactor = () => {
    if (id && connected == true) {
      sendObjectAction(id, 'printer', {
        type: 'setExtrudeFactor',
        data: {
          extrudeFactor: extrudeFactor * 100
        }
      })
    }
  }

  const handleSetMaxVelocity = () => {
    if (id && connected == true) {
      sendObjectAction(id, 'printer', {
        type: 'setMaxVelocity',
        data: {
          maxVelocity: maxVelocity
        }
      })
    }
  }

  const handleSetMaxAcceleration = () => {
    if (id && connected == true) {
      sendObjectAction(id, 'printer', {
        type: 'setMaxAcceleration',
        data: {
          maxAcceleration: maxAcceleration
        }
      })
    }
  }

  const handleSetSquareCornerVelocity = () => {
    if (id && connected == true) {
      sendObjectAction(id, 'printer', {
        type: 'setSquareCornerVelocity',
        data: {
          squareCornerVelocity: squareCornerVelocity
        }
      })
    }
  }

  const handleSetMinCruiseRatio = () => {
    if (id && connected == true) {
      sendObjectAction(id, 'printer', {
        type: 'setMinCruiseRatio',
        data: {
          minCruiseRatio: minCruiseRatio
        }
      })
    }
  }

  const moreInfoItems = [
    {
      key: '1',
      label: 'More Position Data',
      children: (
        <>
          <Divider style={{ margin: '0 0 12px 0' }} />
          <Flex vertical gap={'middle'}>
            <Text>GCode Position:</Text>
            <Descriptions
              column={1}
              size='small'
              bordered
              styles={{ label: { width: '40px' } }}
            >
              <Descriptions.Item label='X'>
                {' '}
                {round(positionData.gcodePosition[0], 2)}mm
              </Descriptions.Item>

              <Descriptions.Item label='Y'>
                {round(positionData.gcodePosition[1], 2)}mm
              </Descriptions.Item>
              <Descriptions.Item label='Z'>
                {round(positionData.gcodePosition[2], 2)}mm
              </Descriptions.Item>
              <Descriptions.Item label='E'>
                {round(positionData.gcodePosition[3], 2)}mm
              </Descriptions.Item>
            </Descriptions>
            {showControls && (
              <>
                <Space direction='vertical' style={{ width: '100%' }}>
                  <Space direction='horizontal'>
                    <Text>Max Velocity:</Text>
                    <Space.Compact block size='small'>
                      <InputNumber
                        value={round(maxVelocity, 2)}
                        min={1}
                        max={10000}
                        step={5}
                        style={{ width: '125px' }}
                        suffix='mm/s'
                        onChange={(value) => setMaxVelocity(value)}
                        onPressEnter={handleSetMaxVelocity}
                        size='small'
                      />
                      <Button
                        type='default'
                        style={{ width: 40 }}
                        onClick={handleSetMaxVelocity}
                      >
                        Set
                      </Button>
                    </Space.Compact>
                  </Space>

                  <Space direction='vertical' style={{ width: '100%' }}>
                    <Space direction='horizontal'>
                      <Text>Max Acceleration:</Text>
                      <Space.Compact block size='small'>
                        <InputNumber
                          value={round(maxAcceleration, 2)}
                          min={1}
                          max={10000}
                          step={5}
                          style={{ width: '125px' }}
                          suffix='mm/s²'
                          onChange={(value) => setMaxAcceleration(value)}
                          onPressEnter={handleSetMaxAcceleration}
                          size='small'
                        />
                        <Button
                          type='default'
                          style={{ width: 40 }}
                          onClick={handleSetMaxAcceleration}
                        >
                          Set
                        </Button>
                      </Space.Compact>
                    </Space>
                  </Space>

                  <Space direction='vertical' style={{ width: '100%' }}>
                    <Space direction='horizontal'>
                      <Text>Sqr Corner Vel:</Text>
                      <Space.Compact block size='small'>
                        <InputNumber
                          value={round(squareCornerVelocity, 2) || 0}
                          min={0.1}
                          max={1000}
                          step={0.1}
                          suffix='mm/s'
                          style={{ width: '125px' }}
                          onChange={(value) => setSquareCornerVelocity(value)}
                          onPressEnter={handleSetSquareCornerVelocity}
                          size='small'
                        />
                        <Button
                          type='default'
                          style={{ width: 40 }}
                          onClick={handleSetSquareCornerVelocity}
                        >
                          Set
                        </Button>
                      </Space.Compact>
                    </Space>
                  </Space>

                  <Space direction='vertical' style={{ width: '100%' }}>
                    <Space direction='horizontal'>
                      <Text>Min Cruise Ratio:</Text>
                      <Space.Compact block size='small'>
                        <InputNumber
                          value={round(minCruiseRatio * 100, 2) || 0}
                          min={0}
                          max={100}
                          step={1}
                          suffix='%'
                          style={{ width: '125px' }}
                          onChange={(value) => setMinCruiseRatio(value / 100)}
                          onPressEnter={handleSetMinCruiseRatio}
                          size='small'
                        />
                        <Button
                          type='default'
                          style={{ width: 40 }}
                          onClick={handleSetMinCruiseRatio}
                        >
                          Set
                        </Button>
                      </Space.Compact>
                    </Space>
                  </Space>
                </Space>
              </>
            )}
            <Text>Homing Origin:</Text>
            <Descriptions
              column={1}
              size='small'
              bordered
              style={{ flexGrow: 1 }}
              styles={{ label: { width: '40px' } }}
            >
              <Descriptions.Item label='X' span={1}>
                {round(positionData.homingOrigin[0], 2)}mm
              </Descriptions.Item>
              <Descriptions.Item label='Y' span={1}>
                {round(positionData.homingOrigin[1], 2)}mm
              </Descriptions.Item>
              <Descriptions.Item label='Z' span={1}>
                {round(positionData.homingOrigin[2], 2)}mm
              </Descriptions.Item>
              <Descriptions.Item label='E'>
                {round(positionData.homingOrigin[3], 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
              styles={{ label: { width: '40px' } }}
            >
              <Descriptions.Item label='X'>
                <Space>
                  <Text>{round(positionData.livePosition[0], 2)}mm</Text>
                  <Text type='secondary'>
                    {round(positionData.toolheadPosition[0], 2)}mm
                  </Text>
                </Space>
              </Descriptions.Item>
              <Descriptions.Item label='Y'>
                <Space>
                  <Text>{round(positionData.livePosition[1], 2)}mm</Text>
                  <Text type='secondary'>
                    {round(positionData.toolheadPosition[1], 2)}mm
                  </Text>
                </Space>
              </Descriptions.Item>
              <Descriptions.Item label='Z'>
                <Space>
                  <Text>{round(positionData.livePosition[2], 2)}mm</Text>
                  <Text type='secondary'>
                    {round(positionData.toolheadPosition[2], 2)}mm
                  </Text>
                </Space>
              </Descriptions.Item>
              <Descriptions.Item label='E'>
                <Space>
                  <Text>{round(positionData.livePosition[3], 2)}mm</Text>
                  <Text type='secondary'>
                    {round(positionData.toolheadPosition[3], 2)}mm
                  </Text>
                </Space>
              </Descriptions.Item>
            </Descriptions>
            {showControls && (
              <>
                <Space direction='vertical' style={{ width: '100%' }}>
                  <Space direction='horizontal'>
                    <Text>Speed Factor:</Text>
                    <Space.Compact block size='small'>
                      <InputNumber
                        value={round(speedFactor, 2)}
                        min={0.1}
                        max={2}
                        step={0.1}
                        style={{ width: '125px' }}
                        suffix='%'
                        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={round(extrudeFactor, 2)}
                        min={0.1}
                        max={2}
                        step={0.1}
                        style={{ width: '125px' }}
                        suffix='%'
                        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
              styles={{ label: { width: '125px' } }}
            >
              <Descriptions.Item label='Speed'>
                {round(positionData.speed, 2)}mm/s
              </Descriptions.Item>
              <Descriptions.Item label='Abs Coor'>
                {positionData ? (
                  <BoolDisplay
                    value={positionData.absoluteCoordinates}
                    yesNo={true}
                  />
                ) : (
                  <Text>n/a</Text>
                )}
              </Descriptions.Item>
              <Descriptions.Item label='Abs Extrude'>
                {positionData ? (
                  <BoolDisplay
                    value={positionData.absoluteExtrude}
                    yesNo={true}
                  />
                ) : (
                  <Text>n/a</Text>
                )}
              </Descriptions.Item>
            </Descriptions>
          </Flex>

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

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

export default PrinterPositionPanel
