import React, { useState, useEffect } from 'react'
import { useLocation } from 'react-router-dom'
import axios from 'axios'
import {
  Descriptions,
  Spin,
  Space,
  Button,
  message,
  Badge,
  Form,
  Typography,
  Flex,
  Input,
  Card,
  Collapse
} from 'antd'
import { LoadingOutlined, CaretRightOutlined } from '@ant-design/icons'
import IdText from '../../common/IdText.jsx'
import { capitalizeFirstLetter } from '../../utils/Utils.js'
import FilamentSelect from '../../common/FilamentSelect'
import useCollapseState from '../../hooks/useCollapseState'
import FilamentIcon from '../../../Icons/FilamentIcon'
import TimeDisplay from '../../common/TimeDisplay.jsx'
import ReloadIcon from '../../../Icons/ReloadIcon'
import EditIcon from '../../../Icons/EditIcon.jsx'
import XMarkIcon from '../../../Icons/XMarkIcon.jsx'
import CheckIcon from '../../../Icons/CheckIcon.jsx'

import config from '../../../../config.js'

const { Title } = Typography

const GCodeFileInfo = () => {
  const [gcodeFileData, setGCodeFileData] = useState(null)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState(null)
  const location = useLocation()
  const [messageApi, contextHolder] = message.useMessage()
  const gcodeFileId = new URLSearchParams(location.search).get('gcodeFileId')
  const [isEditing, setIsEditing] = useState(false)
  const [form] = Form.useForm()
  const [fetchLoading, setFetchLoading] = useState(true)
  const [collapseState, updateCollapseState] = useCollapseState(
    'GCodeFileInfo',
    {
      info: true,
      preview: true
    }
  )

  useEffect(() => {
    if (gcodeFileId) {
      fetchGCodeFileDetails()
    }
  }, [gcodeFileId])

  useEffect(() => {
    if (gcodeFileData) {
      form.setFieldsValue({
        name: gcodeFileData.name || '',
        filament: gcodeFileData.filament || { id: null, name: '' }
      })
    }
  }, [gcodeFileData, form])

  const fetchGCodeFileDetails = async () => {
    try {
      setFetchLoading(true)
      const response = await axios.get(
        `${config.backendUrl}/gcodefiles/${gcodeFileId}`,
        {
          headers: {
            Accept: 'application/json'
          },
          withCredentials: true
        }
      )
      setGCodeFileData(response.data)
      setError(null)
    } catch (err) {
      setError('Failed to fetch GCodeFile details')
      messageApi.error('Failed to fetch GCodeFile details')
    } finally {
      setFetchLoading(false)
    }
  }

  const startEditing = () => {
    setIsEditing(true)
    updateCollapseState('info', true)
  }

  const cancelEditing = () => {
    form.setFieldsValue({
      name: gcodeFileData?.name || '',
      filament: gcodeFileData?.filament || { id: null, name: '' }
    })
    setIsEditing(false)
  }

  const updateInfo = async () => {
    try {
      const values = await form.validateFields()
      setLoading(true)

      await axios.put(
        `${config.backendUrl}/gcodefiles/${gcodeFileId}`,
        values,
        {
          headers: {
            'Content-Type': 'application/json'
          },
          withCredentials: true
        }
      )

      setGCodeFileData({ ...gcodeFileData, ...values })
      setIsEditing(false)
      messageApi.success('GCode File information updated successfully')
    } catch (err) {
      if (err.errorFields) {
        return
      }
      console.error('Failed to update gcode file information:', err)
      messageApi.error('Failed to update gcode file information')
    } finally {
      fetchGCodeFileDetails()
      setLoading(false)
    }
  }

  if (error || !gcodeFileData) {
    return (
      <Space
        direction='vertical'
        style={{ width: '100%', textAlign: 'center' }}
      >
        <p>{error || 'GCodeFile not found'}</p>
        <Button icon={<ReloadIcon />} onClick={fetchGCodeFileDetails}>
          Retry
        </Button>
      </Space>
    )
  }

  if (fetchLoading) {
    return (
      <div style={{ textAlign: 'center', padding: '20px' }}>
        <Spin indicator={<LoadingOutlined style={{ fontSize: 24 }} spin />} />
      </div>
    )
  }

  return (
    <div style={{ height: '100%', minHeight: 0, overflowY: 'auto' }}>
      {contextHolder}
      <Flex vertical gap={'large'}>
        <Collapse
          ghost
          collapsible='icon'
          activeKey={collapseState.info ? ['1'] : []}
          onChange={(keys) => updateCollapseState('info', keys.length > 0)}
          expandIcon={({ isActive }) => (
            <CaretRightOutlined
              rotate={isActive ? 90 : 0}
              style={{ paddingTop: '9px' }}
            />
          )}
          className='no-h-padding-collapse no-t-padding-collapse'
        >
          <Collapse.Panel
            header={
              <Flex
                align='center'
                justify='space-between'
                style={{ width: '100%' }}
              >
                <Title level={5} style={{ margin: 0 }}>
                  GCode File Information
                </Title>
                <Space>
                  {isEditing ? (
                    <>
                      <Button
                        icon={<CheckIcon />}
                        type='primary'
                        onClick={updateInfo}
                        loading={loading}
                      />
                      <Button
                        icon={<XMarkIcon />}
                        onClick={cancelEditing}
                        disabled={loading}
                      />
                    </>
                  ) : (
                    <Button icon={<EditIcon />} onClick={startEditing} />
                  )}
                </Space>
              </Flex>
            }
            key='1'
          >
            <Form form={form} layout='vertical'>
              <Descriptions
                bordered
                column={{
                  xs: 1,
                  sm: 1,
                  md: 1,
                  lg: 2,
                  xl: 2,
                  xxl: 2
                }}
              >
                <Descriptions.Item label='ID' span={1}>
                  {gcodeFileData.id ? (
                    <IdText id={gcodeFileData.id} type='gcodeFile'></IdText>
                  ) : (
                    'n/a'
                  )}
                </Descriptions.Item>
                <Descriptions.Item label='Created At'>
                  <TimeDisplay
                    dateTime={gcodeFileData.createdAt}
                    showSince={true}
                  />
                </Descriptions.Item>

                <Descriptions.Item label='Name'>
                  {isEditing ? (
                    <Form.Item
                      name='name'
                      rules={[
                        {
                          required: true,
                          message: 'Please enter a vendor name'
                        },
                        {
                          max: 100,
                          message: 'Name cannot exceed 100 characters'
                        }
                      ]}
                      style={{ margin: 0 }}
                    >
                      <Input />
                    </Form.Item>
                  ) : (
                    gcodeFileData.name
                  )}
                </Descriptions.Item>

                <Descriptions.Item label='Updated At'>
                  <TimeDisplay
                    dateTime={gcodeFileData.updatedAt}
                    showSince={true}
                  />
                </Descriptions.Item>
                <Descriptions.Item label='Filament Name'>
                  {isEditing ? (
                    <Form.Item
                      name='filament'
                      rules={[
                        { required: true, message: 'Please enter a filament' }
                      ]}
                      style={{ margin: 0 }}
                    >
                      <FilamentSelect />
                    </Form.Item>
                  ) : gcodeFileData.filament ? (
                    <Space>
                      <FilamentIcon />
                      <Badge
                        color={gcodeFileData.filament.color}
                        text={gcodeFileData.filament.name}
                      />
                    </Space>
                  ) : (
                    'n/a'
                  )}
                </Descriptions.Item>
                <Descriptions.Item label='Filament ID'>
                  {gcodeFileData.filament ? (
                    <IdText
                      id={gcodeFileData.filament.id}
                      type={'filament'}
                      showHyperlink={true}
                    />
                  ) : (
                    'n/a'
                  )}
                </Descriptions.Item>
                <Descriptions.Item label='Est Print Time'>
                  {gcodeFileData.gcodeFileInfo
                    .estimatedPrintingTimeNormalMode || 'n/a'}
                </Descriptions.Item>
                <Descriptions.Item label='Cost'>
                  {'£' + gcodeFileData.cost.toFixed(2) || 'n/a'}
                </Descriptions.Item>
                <Descriptions.Item label='Infill Density'>
                  {(() => {
                    if (gcodeFileData.gcodeFileInfo.sparseInfillDensity) {
                      return gcodeFileData.gcodeFileInfo.sparseInfillDensity
                    } else {
                      return 'n/a'
                    }
                  })()}
                </Descriptions.Item>
                <Descriptions.Item label='Infill Pattern'>
                  {(() => {
                    if (gcodeFileData.gcodeFileInfo.sparseInfillPattern) {
                      return capitalizeFirstLetter(
                        gcodeFileData.gcodeFileInfo.sparseInfillPattern
                      )
                    } else {
                      return 'n/a'
                    }
                  })()}
                </Descriptions.Item>
                <Descriptions.Item label='Filament Used (mm)'>
                  {(() => {
                    if (gcodeFileData.gcodeFileInfo.filamentUsedMm) {
                      return `${gcodeFileData.gcodeFileInfo.filamentUsedMm}mm`
                    } else {
                      return 'n/a'
                    }
                  })()}
                </Descriptions.Item>
                <Descriptions.Item label='Filament Used (g)'>
                  {(() => {
                    if (gcodeFileData.gcodeFileInfo.filamentUsedG) {
                      return `${gcodeFileData.gcodeFileInfo.filamentUsedG}g`
                    } else {
                      return 'n/a'
                    }
                  })()}
                </Descriptions.Item>
                <Descriptions.Item label='Hotend Temperature'>
                  {(() => {
                    if (gcodeFileData.gcodeFileInfo.nozzleTemperature) {
                      return `${gcodeFileData.gcodeFileInfo.nozzleTemperature}°`
                    } else {
                      return 'n/a'
                    }
                  })()}
                </Descriptions.Item>
                <Descriptions.Item label='Bed Temperature'>
                  {(() => {
                    if (gcodeFileData.gcodeFileInfo.hotPlateTemp) {
                      return `${gcodeFileData.gcodeFileInfo.hotPlateTemp}°`
                    } else {
                      return 'n/a'
                    }
                  })()}
                </Descriptions.Item>
                <Descriptions.Item label='Filament Profile'>
                  {(() => {
                    if (gcodeFileData.gcodeFileInfo.filamentSettingsId) {
                      return `${gcodeFileData.gcodeFileInfo.filamentSettingsId.replaceAll('"', '')}`
                    } else {
                      return 'n/a'
                    }
                  })()}
                </Descriptions.Item>
                <Descriptions.Item label='Print Profile'>
                  {(() => {
                    if (gcodeFileData.gcodeFileInfo.printSettingsId) {
                      return `${gcodeFileData.gcodeFileInfo.printSettingsId.replaceAll('"', '')}`
                    } else {
                      return 'n/a'
                    }
                  })()}
                </Descriptions.Item>
              </Descriptions>
            </Form>
          </Collapse.Panel>
        </Collapse>

        <Collapse
          ghost
          collapsible='icon'
          activeKey={collapseState.preview ? ['2'] : []}
          onChange={(keys) => updateCollapseState('preview', keys.length > 0)}
          expandIcon={({ isActive }) => (
            <CaretRightOutlined
              rotate={isActive ? 90 : 0}
              style={{ paddingTop: '2px' }}
            />
          )}
          className='no-h-padding-collapse'
        >
          <Collapse.Panel
            header={
              <Title level={5} style={{ margin: 0 }}>
                GCode File Preview
              </Title>
            }
            key='2'
          >
            <Card styles={{ body: { padding: '10px' } }}>
              {gcodeFileData.gcodeFileInfo.thumbnail ? (
                <img
                  src={`data:image/png;base64,${gcodeFileData.gcodeFileInfo.thumbnail.data}`}
                  alt='GCodeFile'
                  style={{ maxWidth: '100%' }}
                />
              ) : (
                'n/a'
              )}
            </Card>
          </Collapse.Panel>
        </Collapse>
      </Flex>
    </div>
  )
}

export default GCodeFileInfo
