import PropTypes from 'prop-types'
import React, { useState, useContext, useEffect, useRef } from 'react'
import axios from 'axios'
import { useMediaQuery } from 'react-responsive'
import {
  Input,
  Button,
  message,
  Typography,
  Flex,
  Steps,
  Divider,
  Upload,
  Descriptions,
  Modal,
  Progress,
  Form,
  Checkbox,
  InputNumber
} from 'antd'
import { DeleteOutlined, EyeOutlined } from '@ant-design/icons'
import { AuthContext } from '../../context/AuthContext'
import PartIcon from '../../../Icons/PartIcon'
import { StlViewer } from 'react-stl-viewer'
import VendorSelect from '../../common/VendorSelect'

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

const { Dragger } = Upload
const { Title, Text } = Typography

const initialNewProductForm = {
  name: '',
  parts: [],
  vendor: null,
  marginOrPrice: false,
  margin: 0,
  price: 0
}

const NewProduct = ({ onOk, reset }) => {
  // UI state
  const [messageApi, contextHolder] = message.useMessage()
  const [currentStep, setCurrentStep] = useState(0)
  const [newProductLoading, setNewProductLoading] = useState(false)
  const [nextEnabled, setNextEnabled] = useState(false)

  const [newProductForm] = Form.useForm()
  const [newProductFormValues, setNewProductFormValues] = useState(
    initialNewProductForm
  )
  const newProductFormUpdateValues = Form.useWatch([], newProductForm)

  // Combined parts and files state
  const [parts, setParts] = useState([])
  const [fileUrls, setFileUrls] = useState({})
  const [uploadProgress, setUploadProgress] = useState({})

  // Preview state
  const [previewVisible, setPreviewVisible] = useState(false)
  const [previewFile, setPreviewFile] = useState(null)
  const [isPreviewLoading, setIsPreviewLoading] = useState(false)
  const previewTimerRef = useRef(null)

  const [marginOrPrice, setMarginOrPrice] = useState(false)

  const { token, authenticated } = useContext(AuthContext)

  const isMobile = useMediaQuery({ maxWidth: 768 })

  useEffect(() => {
    newProductForm
      .validateFields({
        validateOnly: true
      })
      .then(() => setNextEnabled(true))
      .catch(() => setNextEnabled(false))
  }, [newProductForm, newProductFormUpdateValues])

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

  useEffect(() => {
    setMarginOrPrice(newProductFormValues.marginOrPrice)
  }, [newProductFormValues])

  // Effect: Cleanup file URLs on unmount
  useEffect(() => {
    return () => {
      Object.values(fileUrls).forEach(URL.revokeObjectURL)
      if (previewTimerRef.current) {
        clearTimeout(previewTimerRef.current)
      }
    }
  }, [fileUrls])

  useEffect(() => {
    setNewProductFormValues((prev) => ({ ...prev, parts: parts }))
  }, [parts, setNewProductFormValues])

  // File handlers
  const handleFileAdd = (file) => {
    const objectUrl = URL.createObjectURL(file)
    const defaultName = file.name.replace(/\.[^/.]+$/, '')

    setParts((prev) => [
      {
        name: defaultName,
        file,
        uid: file.uid
      },
      ...prev
    ])

    setFileUrls((prev) => ({ ...prev, [file.uid]: objectUrl }))
    setUploadProgress((prev) => ({ ...prev, [file.uid]: 0 }))

    return false // Prevent default upload
  }

  const handleFileRemove = (index) => {
    setParts((prev) => {
      const newParts = [...prev]
      const removedPart = newParts[index]
      newParts.splice(index, 1)

      // Cleanup URL and progress
      if (removedPart && fileUrls[removedPart.uid]) {
        URL.revokeObjectURL(fileUrls[removedPart.uid])
        setFileUrls((urls) => {
          const newUrls = { ...urls }
          delete newUrls[removedPart.uid]
          return newUrls
        })
        setUploadProgress((progress) => {
          const newProgress = { ...progress }
          delete newProgress[removedPart.uid]
          return newProgress
        })
      }

      return newParts
    })
  }

  const handleNameChange = (index, newName) => {
    setParts((prev) => {
      const newParts = [...prev]
      newParts[index] = { ...newParts[index], name: newName }
      return newParts
    })
  }

  const handlePreview = (file) => {
    setPreviewFile(file)
    setPreviewVisible(true)
    setIsPreviewLoading(true)

    if (previewTimerRef.current) {
      clearTimeout(previewTimerRef.current)
    }
    previewTimerRef.current = setTimeout(() => {
      setIsPreviewLoading(false)
    }, 300)
  }

  const handleNewProduct = async () => {
    setNewProductLoading(true)
    try {
      const result = await axios.post(
        `${config.backendUrl}/products`,
        newProductFormValues,
        {
          withCredentials: true // Important for including cookies
        }
      )
      await uploadParts(result.data.parts)
      onOk()
    } catch (error) {
      messageApi.error('Error creating new product: ' + error.message)
    } finally {
      setNewProductLoading(false)
    }
  }

  // Submit handler
  const uploadParts = async (partIds) => {
    if (!authenticated) return

    try {
      // Upload files sequentially for each part
      for (let i = 0; i < parts.length; i++) {
        const formData = new FormData()
        formData.append('partFile', parts[i].file)

        await axios.post(
          `${config.backendUrl}/parts/${partIds[i]}/content`,
          formData,
          {
            headers: {
              'Content-Type': 'multipart/form-data',
              Authorization: `Bearer ${token}`
            },
            onUploadProgress: (progressEvent) => {
              const percentCompleted = Math.round(
                (progressEvent.loaded * 100) / progressEvent.total
              )
              setUploadProgress((prev) => ({
                ...prev,
                [parts[i].uid]: percentCompleted
              }))
            }
          }
        )
      }
    } catch (error) {
      messageApi.error('Error creating product: ' + error.message)
    }
  }

  // Step Contents
  const uploadStep = (
    <Flex gap='middle' vertical>
      {parts.length != 0 ? (
        <div style={{ maxHeight: '200px', overflowY: 'scroll' }}>
          <Flex vertical gap='small'>
            {parts.map((part, index) => (
              <Flex key={part.uid} gap='small' align='center'>
                <Input
                  placeholder='Part name'
                  value={part.name}
                  onChange={(e) => handleNameChange(index, e.target.value)}
                  style={{ flex: 1 }}
                />
                <Button
                  icon={<EyeOutlined />}
                  onClick={() => handlePreview(part.file)}
                />
                <Button
                  danger
                  icon={<DeleteOutlined />}
                  onClick={() => handleFileRemove(index)}
                />
              </Flex>
            ))}
          </Flex>
        </div>
      ) : null}

      <Dragger
        name='parts'
        multiple
        fileList={[]}
        showUploadList={false}
        beforeUpload={handleFileAdd}
        customRequest={({ onSuccess }) => setTimeout(() => onSuccess('ok'), 0)}
      >
        <Flex style={{ height: '100%' }} vertical>
          <p className='ant-upload-drag-icon'>
            <PartIcon />
          </p>
          <p className='ant-upload-text'>Click or drag 3D Model files here</p>
          <p className='ant-upload-hint'>
            Supported file extensions: .stl, .3mf
          </p>
        </Flex>
      </Dragger>
    </Flex>
  )

  const detailsStep = (
    <>
      <Form.Item
        label='Name'
        name='name'
        rules={[
          {
            required: true,
            message: 'Please enter a name.'
          }
        ]}
      >
        <Input placeholder='Enter product name' />
      </Form.Item>
      <Form.Item
        label='Vendor'
        name='vendor'
        rules={[
          {
            required: true,
            message: 'Please enter a vendor.'
          }
        ]}
      >
        <VendorSelect />
      </Form.Item>
      <Flex gap='middle'>
        {marginOrPrice == false ? (
          <Form.Item
            label={'Margin'}
            name='margin'
            style={{ flexGrow: 1 }}
            rules={[
              {
                required: true,
                message: 'Please enter a margin.'
              }
            ]}
          >
            <InputNumber
              controls={false}
              step={0.01}
              style={{ width: '100%' }}
              addonAfter='%'
            />
          </Form.Item>
        ) : (
          <Form.Item
            label={'Price'}
            name='price'
            style={{ 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'>
          <Checkbox>Price</Checkbox>
        </Form.Item>
      </Flex>
    </>
  )

  const summaryStep = (
    <Descriptions
      column={1}
      size='small'
      items={[
        {
          key: 'name',
          label: 'Name',
          children: <Text>{newProductFormValues?.name}</Text>
        },
        {
          key: 'vendor',
          label: 'Vendor',
          children: <Text>{newProductFormValues?.vendor?.name}</Text>
        },
        {
          key: 'marginPrice',
          label: !marginOrPrice ? 'Margin' : 'Price',
          children: !marginOrPrice ? (
            <Text>{newProductFormValues?.margin}%</Text>
          ) : (
            <Text>£{newProductFormValues?.price}</Text>
          )
        },
        ...parts.map((part, index) => ({
          key: part.uid,
          label: `Part ${index + 1}`,
          children: (
            <Flex gap='middle' align='center'>
              <span>{part.name}</span>
              <Progress
                percent={uploadProgress[part.uid] || 0}
                size='small'
                style={{ width: '120px', marginBottom: 0 }}
              />
            </Flex>
          )
        }))
      ]}
    />
  )

  const steps = [
    { title: 'Upload Parts', content: uploadStep },
    { title: 'Details', content: detailsStep },
    { title: 'Summary', content: summaryStep }
  ]

  return (
    <Flex gap='middle'>
      {contextHolder}

      {!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 gap='middle' style={{ flexGrow: 1 }}>
        <Title level={2} style={{ marginTop: 0, marginBottom: 4 }}>
          New Product
        </Title>

        <Form
          name='basic'
          autoComplete='off'
          form={newProductForm}
          onFinish={handleNewProduct}
          onValuesChange={(changedValues) =>
            setNewProductFormValues((prevValues) => ({
              ...prevValues,
              ...changedValues
            }))
          }
          initialValues={initialNewProductForm}
        >
          <div style={{ minHeight: '260px' }}>{steps[currentStep].content}</div>
        </Form>

        <Flex justify='end'>
          <Button
            style={{ margin: '0 8px' }}
            onClick={() => {
              setCurrentStep((prev) => prev - 1)
              setNextEnabled(true)
            }}
            disabled={currentStep === 0}
          >
            Previous
          </Button>

          {currentStep < steps.length - 1 ? (
            <Button
              type='primary'
              disabled={!nextEnabled}
              onClick={() => {
                setCurrentStep((prev) => prev + 1)
                setNextEnabled(false)
              }}
            >
              Next
            </Button>
          ) : (
            <Button
              type='primary'
              loading={newProductLoading}
              onClick={() => {
                newProductForm.submit()
              }}
            >
              Done
            </Button>
          )}
        </Flex>
      </Flex>

      <Modal
        open={previewVisible}
        footer={null}
        onCancel={() => {
          setPreviewVisible(false)
          setPreviewFile(null)
          if (previewTimerRef.current) {
            clearTimeout(previewTimerRef.current)
          }
        }}
        style={{ top: 30 }}
        width='90%'
      >
        <Flex style={{ minWidth: '100%', minHeight: '80vh' }}>
          {previewFile && !isPreviewLoading ? (
            <div style={{ flexGrow: 1 }}>
              <StlViewer
                url={fileUrls[previewFile.uid]}
                orbitControls
                shadows
                style={{ height: '80vh', width: '100%' }}
                modelProps={{ color: '#008675' }}
              />
            </div>
          ) : (
            <div
              style={{
                flexGrow: 1,
                display: 'flex',
                justifyContent: 'center',
                alignItems: 'center',
                height: '80vh'
              }}
            >
              Loading 3D model...
            </div>
          )}
        </Flex>
      </Modal>
    </Flex>
  )
}

NewProduct.propTypes = {
  reset: PropTypes.bool.isRequired,
  onOk: PropTypes.func.isRequired
}

export default NewProduct
