import { useContext, useState, useEffect } from 'react'
import { Typography, Spin, Flex, Space, Slider, Descriptions, Tag } from 'antd'
import { LoadingOutlined } from '@ant-design/icons'
import { ApiServerContext } from '../context/ApiServerContext'
import PropTypes from 'prop-types'
import merge from 'lodash/merge'

const { Text } = Typography

const PrinterMiscPanel = ({
  id,
  showControls = true,
  disabled = false,
  offline = true
}) => {
  const { subscribeToObjectEvent, connected, sendObjectAction } =
    useContext(ApiServerContext)
  const controlsDisabled = disabled || !connected
  const [miscData, setMiscData] = useState({
    fan: {
      speed: 0,
      target: 0
    },
    lcdBacklight: {
      brightness: 0
    },
    beeper: {
      value: 0
    },
    filamentSensor: {
      enabled: false,
      filamentDetected: false
    },
    coolingFan: {
      speed: 0
    }
  })

  const [fanSpeed, setFanSpeed] = useState(0)
  const [lcdBrightness, setLcdBrightness] = useState(0)
  const [beeperValue, setBeeperValue] = useState(0)

  useEffect(() => {
    if (offline) {
      setMiscData({
        fan: { speed: 0, target: 0 },
        lcdBacklight: { brightness: 0 },
        beeper: { value: 0 },
        filamentSensor: { enabled: false, filamentDetected: false },
        coolingFan: { speed: 0 }
      })
    }
  }, [offline])

  useEffect(() => {
    if (id && connected == true) {
      const miscEventUnsubscribe = subscribeToObjectEvent(
        id?.toLowerCase(),
        'printer',
        'misc',
        (event) => {
          setMiscData((prev) => {
            const merged = merge({}, prev, event.data)
            return merged
          })
        }
      )
      return () => {
        if (miscEventUnsubscribe) miscEventUnsubscribe()
      }
    }
  }, [id, connected, subscribeToObjectEvent])

  useEffect(() => {
    if (miscData.fan?.speed !== undefined) {
      setFanSpeed(miscData.fan.speed)
    }
    if (miscData.lcdBacklight?.brightness !== undefined) {
      setLcdBrightness(miscData.lcdBacklight.brightness)
    }
    if (miscData.beeper?.value !== undefined) {
      setBeeperValue(miscData.beeper.value)
    }
  }, [
    miscData.fan?.speed,
    miscData.lcdBacklight?.brightness,
    miscData.beeper?.value
  ])

  const handleSetFanSpeed = (value) => {
    if (id && connected == true) {
      sendObjectAction(id, 'printer', {
        type: 'gcodeScript',
        data: {
          script: `M106 S${Math.round(value * 255)}`
        }
      })
    }
  }

  const handleSetLcdBrightness = (value) => {
    if (id && connected == true) {
      sendObjectAction(id, 'printer', {
        type: 'gcodeScript',
        data: {
          script: `SET_PIN PIN=LCD_backlight_pin VALUE=${value}`
        }
      })
    }
  }

  const handleSetBeeperValue = (value) => {
    if (id && connected == true) {
      sendObjectAction(id, 'printer', {
        type: 'gcodeScript',
        data: {
          script: `SET_PIN PIN=BEEPER_pin VALUE=${Math.round(value * 1000)}.00`
        }
      })
    }
  }

  return (
    <div style={{ minWidth: 190 }}>
      {miscData ? (
        <Flex vertical gap='middle'>
          <Flex vertical gap={'middle'}>
            {showControls && (
              <>
                <Space direction='vertical' style={{ width: '100%' }}>
                  <Text>Fan Speed: {Math.round(fanSpeed * 100)}%</Text>
                  <Slider
                    value={fanSpeed}
                    min={0}
                    max={1}
                    step={0.01}
                    disabled={controlsDisabled}
                    onChange={setFanSpeed}
                    onAfterChange={handleSetFanSpeed}
                    tooltip={{ open: false }}
                  />

                  <Text>LCD Backlight: {Math.round(lcdBrightness * 100)}%</Text>
                  <Slider
                    value={lcdBrightness}
                    min={0}
                    max={1}
                    step={0.01}
                    disabled={controlsDisabled}
                    onChange={setLcdBrightness}
                    onAfterChange={handleSetLcdBrightness}
                    tooltip={{ open: false }}
                  />

                  <Text>Beeper Pitch: {Math.round(beeperValue * 100)}%</Text>
                  <Slider
                    value={beeperValue}
                    min={0}
                    max={1}
                    step={0.01}
                    disabled={controlsDisabled}
                    onChange={setBeeperValue}
                    onAfterChange={handleSetBeeperValue}
                    tooltip={{ open: false }}
                  />
                </Space>
              </>
            )}

            <Descriptions column={1} size='small' bordered>
              <Descriptions.Item label='Filament Sensor'>
                {miscData.filamentSensor.enabled ? (
                  miscData.filamentSensor.filamentDetected ? (
                    <Tag color='green'>Detected</Tag>
                  ) : (
                    <Tag color='red'>Open</Tag>
                  )
                ) : (
                  <Tag color='default'>Disabled</Tag>
                )}
              </Descriptions.Item>
              <Descriptions.Item label='Part Cooling Fan'>
                {miscData.fan.speed > 0 ? (
                  <Text>Running ({Math.round(miscData.fan.speed * 100)}%)</Text>
                ) : (
                  <Text>Off</Text>
                )}
              </Descriptions.Item>
              <Descriptions.Item label='Nozzle Cooling Fan'>
                {miscData.coolingFan.speed > 0 ? (
                  <Text>
                    Running ({Math.round(miscData.coolingFan.speed * 100)}%)
                  </Text>
                ) : (
                  <Text>Off</Text>
                )}
              </Descriptions.Item>
            </Descriptions>
          </Flex>
        </Flex>
      ) : (
        <Flex justify='centre'>
          <Spin indicator={<LoadingOutlined spin />} size='large' />
        </Flex>
      )}
    </div>
  )
}

PrinterMiscPanel.propTypes = {
  id: PropTypes.string.isRequired,
  showControls: PropTypes.bool,
  disabled: PropTypes.bool,
  offline: PropTypes.bool
}

export default PrinterMiscPanel
