import React, { useState, useEffect, useRef } from 'react'
import { useLocation } from 'react-router-dom'
import axios from 'axios'
import {
  Descriptions,
  Spin,
  Space,
  Button,
  message,
  Typography,
  Card,
  Flex,
  Form,
  Input,
  Checkbox,
  InputNumber,
  Switch,
  Tag,
  Collapse
} from 'antd'
import { LoadingOutlined, CaretRightOutlined } from '@ant-design/icons'
import IdText from '../../common/IdText.jsx'
import { StlViewer } from 'react-stl-viewer'
import ReloadIcon from '../../../Icons/ReloadIcon'
import EditIcon from '../../../Icons/EditIcon.jsx'
import XMarkIcon from '../../../Icons/XMarkIcon.jsx'
import CheckIcon from '../../../Icons/CheckIcon.jsx'
import useCollapseState from '../../hooks/useCollapseState'
import TimeDisplay from '../../common/TimeDisplay.jsx'

const { Title } = Typography

const PartInfo = () => {
  const [partData, setPartData] = useState(null)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState(null)
  const location = useLocation()
  const [messageApi, contextHolder] = message.useMessage()
  const partId = new URLSearchParams(location.search).get('partId')
  const [marginOrPrice, setMarginOrPrice] = useState(false)
  const [useGlobalPricing, setUseGlobalPricing] = useState(true)
  const [collapseState, updateCollapseState] = useCollapseState('PartInfo', {
    info: true,
    preview: true
  })

  const [partForm] = Form.useForm()
  const [partFormValues, setPartFormValues] = useState({})

  // Add a ref to store the object URL
  const objectUrlRef = useRef(null)
  // Add a ref to store the array buffer
  const arrayBufferRef = useRef(null)

  const [isEditing, setIsEditing] = useState(false)
  const [fetchLoading, setFetchLoading] = useState(true)

  const [partFileObjectId, setPartFileObjectId] = useState(null)
  const [stlLoadError, setStlLoadError] = useState(null)

  useEffect(() => {
    async function fetchData() {
      await fetchPartDetails()
      setTimeout(async () => {
        await fetchPartContent()
      }, 1000)
    }
    if (partId) {
      fetchData()
    }
  }, [partId])

  useEffect(() => {
    if (partData) {
      partForm.setFieldsValue({
        name: partData.name || '',
        price: partData.price || null,
        margin: partData.margin || null,
        marginOrPrice: partData.marginOrPrice,
        useGlobalPricing: partData.useGlobalPricing,
        createdAt: partData.createdAt || null,
        updatedAt: partData.updatedAt || null
      })
      setPartFormValues(partData)
    }
  }, [partData, partForm])

  useEffect(() => {
    setMarginOrPrice(partFormValues.marginOrPrice)
    setUseGlobalPricing(partFormValues.useGlobalPricing)
  }, [partFormValues])

  const fetchPartDetails = async () => {
    try {
      setFetchLoading(true)
      const response = await axios.get(
        `http://localhost:8080/parts/${partId}`,
        {
          headers: {
            Accept: 'application/json'
          },
          withCredentials: true
        }
      )
      setPartData(response.data)
      setError(null)
    } catch (err) {
      setError('Failed to fetch part details')
      console.log(err)
      messageApi.error('Failed to fetch part details')
    } finally {
      setFetchLoading(false)
    }
  }

  const fetchPartContent = async () => {
    if (fetchLoading == true) {
      return
    }
    try {
      setFetchLoading(true)
      // Cleanup previous object URL if it exists
      if (objectUrlRef.current) {
        URL.revokeObjectURL(objectUrlRef.current)
        objectUrlRef.current = null
      }
      const response = await axios.get(
        `http://localhost:8080/parts/${partId}/content`,
        {
          withCredentials: true,
          responseType: 'blob'
        }
      )

      // Check file size before processing
      const MAX_FILE_SIZE = 100 * 1024 * 1024 // 100MB
      if (response.data.size > MAX_FILE_SIZE) {
        throw new Error(
          `File size exceeds ${MAX_FILE_SIZE / (1024 * 1024)}MB limit`
        )
      }

      // Convert blob to array buffer for better memory management
      const arrayBuffer = await response.data.arrayBuffer()

      // Store array buffer in ref for later cleanup
      arrayBufferRef.current = arrayBuffer

      // Create a new blob from the array buffer
      const blob = new Blob([arrayBuffer], { type: response.data.type })

      try {
        // Create and store object URL
        const objectUrl = URL.createObjectURL(blob)
        objectUrlRef.current = objectUrl

        // Update state with the new object URL
        setPartFileObjectId(objectUrl)
        setStlLoadError(null)
        setError(null)
      } catch (allocErr) {
        setStlLoadError(
          'Failed to load STL file: Array buffer allocation failed'
        )
        console.error('STL allocation error:', allocErr)
      }
    } catch (err) {
      setError('Failed to fetch part content')
      console.log(err)
      messageApi.error('Failed to fetch part content')
    } finally {
      setFetchLoading(false)
    }
  }

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

  const cancelEditing = () => {
    partForm.setFieldsValue({
      name: partData?.name || ''
    })
    setIsEditing(false)
  }

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

      await axios.put(`http://localhost:8080/parts/${partId}`, values, {
        headers: {
          'Content-Type': 'application/json'
        },
        withCredentials: true
      })

      // Update the local state with the new values
      setPartData({ ...partData, ...values })
      setIsEditing(false)
      messageApi.success('Part information updated successfully')
    } catch (err) {
      if (err.errorFields) {
        // This is a form validation error
        return
      }
      console.error('Failed to update part information:', err)
      messageApi.error('Failed to update part information')
    } finally {
      fetchPartDetails()
      setLoading(false)
    }
  }

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

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

  return (
    <div style={{ height: '100%', minHeight: 0, overflowY: 'auto' }}>
      {contextHolder}
      <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' }}
          />
        )}
      >
        <Collapse.Panel
          header={
            <Flex
              align='center'
              justify='space-between'
              style={{ width: '100%' }}
            >
              <Title level={5} style={{ margin: 0 }}>
                Part 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={partForm}
            layout='vertical'
            onValuesChange={(changedValues) =>
              setPartFormValues((prevValues) => ({
                ...prevValues,
                ...changedValues
              }))
            }
            initialValues={{
              name: partData.name || '',
              version: partData.version || '',
              tags: partData.tags || []
            }}
          >
            <Descriptions
              bordered
              column={{
                xs: 1,
                sm: 1,
                md: 1,
                lg: 2,
                xl: 2,
                xxl: 2
              }}
            >
              <Descriptions.Item label='ID' span={1}>
                {partData.id ? (
                  <IdText id={partData.id} type='part'></IdText>
                ) : (
                  'n/a'
                )}
              </Descriptions.Item>
              <Descriptions.Item label='Created At'>
                <TimeDisplay dateTime={partData.createdAt} showSince={true} />
              </Descriptions.Item>

              <Descriptions.Item label='Name' span={1}>
                {isEditing ? (
                  <Form.Item
                    name='name'
                    rules={[
                      {
                        required: true,
                        message: 'Please enter a product name'
                      },
                      { max: 100, message: 'Name cannot exceed 100 characters' }
                    ]}
                    style={{ margin: 0 }}
                  >
                    <Input placeholder='Enter product name' />
                  </Form.Item>
                ) : (
                  partData.name || 'n/a'
                )}
              </Descriptions.Item>

              <Descriptions.Item label='Updated At'>
                <TimeDisplay dateTime={partData.updatedAt} showSince={true} />
              </Descriptions.Item>

              <Descriptions.Item label='Product Name' span={1}>
                {partData.product.name || 'n/a'}
              </Descriptions.Item>
              <Descriptions.Item label='Product ID' span={1}>
                {(
                  <IdText
                    id={partData.product._id}
                    type={'product'}
                    showHyperlink={true}
                  />
                ) || 'n/a'}
              </Descriptions.Item>
              <Descriptions.Item
                label={!marginOrPrice ? 'Margin' : 'Price'}
                span={1}
              >
                {isEditing && useGlobalPricing == false ? (
                  <Flex gap='middle'>
                    {marginOrPrice == false ? (
                      <Form.Item
                        name='margin'
                        style={{ margin: 0, flexGrow: 1 }}
                        rules={[
                          {
                            required: true,
                            message: 'Please enter a margin.'
                          }
                        ]}
                      >
                        <InputNumber
                          controls={false}
                          step={0.01}
                          style={{ width: '100%' }}
                          addonAfter='%'
                        />
                      </Form.Item>
                    ) : (
                      <Form.Item
                        name='price'
                        style={{ margin: 0, flexGrow: 1 }}
                        rules={[
                          {
                            required: true,
                            message: 'Please enter a price.'
                          }
                        ]}
                      >
                        <InputNumber
                          controls={false}
                          step={0.01}
                          style={{ width: '100%' }}
                          addonBefore='£'
                        />
                      </Form.Item>
                    )}
                    <Form.Item
                      name='marginOrPrice'
                      valuePropName='checked'
                      style={{ margin: 0 }}
                    >
                      <Checkbox>Price</Checkbox>
                    </Form.Item>
                  </Flex>
                ) : partData.margin &&
                  marginOrPrice == false &&
                  partData.useGlobalPricing == false ? (
                  partData.margin + '%'
                ) : partData.price &&
                  marginOrPrice == true &&
                  partData.useGlobalPricing == false ? (
                  '£' + partData.price
                ) : (
                  'n/a'
                )}
              </Descriptions.Item>
              <Descriptions.Item label='Global Pricing'>
                {isEditing ? (
                  <Form.Item
                    name='useGlobalPricing'
                    rules={[
                      {
                        required: true,
                        message: 'Please enter a global price method'
                      }
                    ]}
                    style={{ margin: 0 }}
                    valuePropName='checked'
                  >
                    <Switch />
                  </Form.Item>
                ) : partData.useGlobalPricing == true ? (
                  <Tag color='success' icon={<CheckIcon />}>
                    Yes
                  </Tag>
                ) : partData.useGlobalPricing == false ? (
                  <Tag icon={<XMarkIcon />}>No</Tag>
                ) : (
                  'n/a'
                )}
              </Descriptions.Item>
              <Descriptions.Item label='Version' span={1}>
                {partData.version || 'n/a'}
              </Descriptions.Item>
              <Descriptions.Item label='Tags'>
                {partData.tags &&
                  partData.tags.map((tag, index) => (
                    <Tag key={index}>{tag}</Tag>
                  ))}
              </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' }}
          />
        )}
      >
        <Collapse.Panel
          header={
            <Title level={5} style={{ margin: 0 }}>
              Part Preview
            </Title>
          }
          key='2'
        >
          <Card styles={{ body: { padding: '10px' } }}>
            {stlLoadError ? (
              <div
                style={{
                  height: '40vw',
                  display: 'flex',
                  alignItems: 'center',
                  justifyContent: 'center',
                  backgroundColor: '#f5f5f5'
                }}
              >
                <Space direction='vertical' align='center'>
                  <XMarkIcon style={{ fontSize: '24px', color: '#ff4d4f' }} />
                  <Typography.Text type='danger'>
                    {stlLoadError}
                  </Typography.Text>
                </Space>
              </div>
            ) : (
              partFileObjectId && (
                <StlViewer
                  url={partFileObjectId}
                  orbitControls
                  shadows
                  style={{ height: '40vw' }}
                  modelProps={{
                    color: '#008675'
                  }}
                ></StlViewer>
              )
            )}
          </Card>
        </Collapse.Panel>
      </Collapse>
    </div>
  )
}

export default PartInfo
