import { useState, useContext, useEffect } from 'react'
import { Form, Button, Typography, Flex, Steps, Divider, Alert } from 'antd'
import { useMediaQuery } from 'react-responsive'
import PropTypes from 'prop-types'
import { PrintServerContext } from '../../context/PrintServerContext'

import PrinterSelect from '../../common/PrinterSelect'
import PrinterTemperaturePanel from '../../common/PrinterTemperaturePanel'

import { LoadingOutlined } from '@ant-design/icons'

const { Title } = Typography

const UnloadFilamentStock = ({ onOk, reset, printer = null }) => {
  UnloadFilamentStock.propTypes = {
    onOk: PropTypes.func.isRequired,
    reset: PropTypes.bool.isRequired,
    printer: PropTypes.object
  }

  const { printServer } = useContext(PrintServerContext)
  const isMobile = useMediaQuery({ maxWidth: 768 })

  const initialUnloadFilamentStockForm = {
    printer: printer
  }

  const [unloadFilamentStockLoading, setUnloadFilamentStockLoading] =
    useState(false)
  const [currentStep, setCurrentStep] = useState(0)
  const [nextEnabled, setNextEnabled] = useState(false)
  const [currentTemperature, setCurrentTemperature] = useState(-1)
  const [targetTemperature, setTargetTemperature] = useState(0)
  const [filamentSensorDetected, setFilamentSensorDetected] = useState(true)
  const [unloadFilamentStockForm] = Form.useForm()
  const [unloadFilamentStockFormValues, setUnloadFilamentStockFormValues] =
    useState(initialUnloadFilamentStockForm)

  // Add websocket temperature monitoring
  useEffect(() => {
    if (unloadFilamentStockFormValues.printer) {
      const params = {
        printerId: unloadFilamentStockFormValues.printer._id,
        objects: {
          extruder: null,
          'filament_switch_sensor fsensor': null
        }
      }

      const notifyStatusUpdate = (statusUpdate) => {
        if (statusUpdate?.extruder?.temperature !== undefined) {
          setCurrentTemperature(statusUpdate.extruder.temperature)
        }
        if (statusUpdate?.extruder?.target !== undefined) {
          setTargetTemperature(statusUpdate.extruder.target)
        }
        if (
          statusUpdate?.['filament_switch_sensor fsensor']
            ?.filament_detected !== undefined
        ) {
          setFilamentSensorDetected(
            Boolean(
              statusUpdate['filament_switch_sensor fsensor'].filament_detected
            )
          )
        }
      }

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

      return () => {
        printServer.off('notify_status_update', notifyStatusUpdate)
        printServer.emit('printer.objects.unsubscribe', params)
      }
    }
  }, [printServer, unloadFilamentStockFormValues.printer])

  useEffect(() => {
    if (reset) {
      unloadFilamentStockForm.resetFields()
    }
  }, [reset, unloadFilamentStockForm])

  useEffect(() => {
    unloadFilamentStockForm
      .validateFields({
        validateOnly: true
      })
      .then(() => {
        // Only enable next if we have a printer selected, we're not loading, and we've reached target temperature
        setNextEnabled(
          Boolean(unloadFilamentStockFormValues.printer) &&
            !unloadFilamentStockLoading &&
            currentTemperature + 1 > targetTemperature &&
            targetTemperature != 0
        )
      })
      .catch(() => setNextEnabled(false))
  }, [
    unloadFilamentStockForm,
    unloadFilamentStockFormValues,
    unloadFilamentStockLoading,
    currentTemperature,
    targetTemperature
  ])

  const handleUnloadFilamentStock = async () => {
    setUnloadFilamentStockLoading(true)
    // Send G-code to retract the filament
    await printServer.emit('printer.gcode.script', {
      printerId: unloadFilamentStockFormValues.printer._id,
      script: `_CLIENT_LINEAR_MOVE E=-200 F=1000`
    })
    //setUnloadFilamentStockLoading(false)
  }

  useEffect(() => {
    if (unloadFilamentStockLoading == true && filamentSensorDetected == false) {
      setUnloadFilamentStockLoading(false)
      onOk()
    }
  }, [unloadFilamentStockLoading, filamentSensorDetected, onOk])

  const steps = [
    {
      title: 'Preheat',
      key: 'preHeat',
      content: (
        <Flex vertical gap={'middle'} style={{ paddingBottom: 16 }}>
          <Form.Item
            label='Printer'
            name='printer'
            style={{ margin: 0 }}
            rules={[
              {
                required: true,
                message: 'Please select a printer'
              }
            ]}
          >
            <PrinterSelect checkable={false} />
          </Form.Item>

          {unloadFilamentStockLoading == false ? (
            <>
              {targetTemperature == 0 ? (
                <Alert
                  message={'Heat the extruder to start unloading filament.'}
                  type='info'
                  showIcon
                />
              ) : null}

              {targetTemperature > 0 &&
              currentTemperature < targetTemperature ? (
                <Alert
                  message={'Heating extruder...'}
                  type='error'
                  showIcon
                  icon={<LoadingOutlined />}
                />
              ) : null}

              {targetTemperature > 0 &&
              currentTemperature + 1 > targetTemperature &&
              filamentSensorDetected ? (
                <Alert
                  message={'Ready to unload filament stock.'}
                  type='success'
                  showIcon
                />
              ) : null}
            </>
          ) : (
            <Alert
              message={'Unloading filament stock...'}
              type='info'
              showIcon
              icon={<LoadingOutlined />}
            />
          )}

          {unloadFilamentStockFormValues.printer ? (
            <PrinterTemperaturePanel
              showHeatedBed={false}
              showMoreInfo={false}
              printerId={unloadFilamentStockFormValues.printer._id}
            />
          ) : null}
        </Flex>
      )
    }
  ]

  return (
    <Flex gap={'middle'}>
      {!isMobile && (
        <div style={{ minWidth: '160px' }}>
          <Steps
            current={currentStep}
            items={steps}
            direction='vertical'
            style={{ width: 'fit-content' }}
          />
        </div>
      )}

      {!isMobile && <Divider type={'vertical'} style={{ height: 'unset' }} />}

      <Flex vertical={'true'} style={{ flexGrow: 1 }} gap='middle'>
        <Title level={2} style={{ marginTop: 0, marginBottom: 4 }}>
          Unload Filament Stock
        </Title>
        <Form
          name='unloadFilamentStock'
          autoComplete='off'
          form={unloadFilamentStockForm}
          onFinish={handleUnloadFilamentStock}
          onValuesChange={(changedValues) =>
            setUnloadFilamentStockFormValues((prevValues) => ({
              ...prevValues,
              ...changedValues
            }))
          }
          initialValues={initialUnloadFilamentStockForm}
        >
          <div style={{ minHeight: '260px' }}>{steps[currentStep].content}</div>

          <Flex justify={'end'}>
            <Button
              style={{
                margin: '0 8px'
              }}
              onClick={() => setCurrentStep(currentStep - 1)}
              disabled={!(currentStep > 0)}
            >
              Previous
            </Button>
            {currentStep === steps.length - 1 && (
              <Button
                type='primary'
                loading={unloadFilamentStockLoading}
                disabled={!nextEnabled}
                onClick={() => {
                  unloadFilamentStockForm.submit()
                }}
              >
                {unloadFilamentStockLoading ? 'Unloading...' : 'Unload'}
              </Button>
            )}
          </Flex>
        </Form>
      </Flex>
    </Flex>
  )
}

export default UnloadFilamentStock
