import { useEffect, useState } from 'react'
import { createPortal } from 'react-dom'
import { X } from 'lucide-react'
import { ApiError } from '../lib/api'
import {
  getProductTechnicalInfo,
  saveProductTechnicalInfo,
  valuesToFormState,
} from '../services/productTechnicalInfoService'
import type {
  CategoryTechnicalForm,
  ProductTechnicalFormValues,
  TechnicalFieldType,
} from '../types/technicalForm'
import styles from './VariationsModal.module.css'
import fieldStyles from './TechnicalFormModal.module.css'

interface ProductTechnicalInfoModalProps {
  open: boolean
  productId: string
  productName: string
  categoryId: string
  onClose: () => void
}

const ANIMATION_MS = 220

export function ProductTechnicalInfoModal({
  open,
  productId,
  productName,
  categoryId,
  onClose,
}: ProductTechnicalInfoModalProps) {
  const [mounted, setMounted] = useState(open)
  const [closing, setClosing] = useState(false)
  const [form, setForm] = useState<CategoryTechnicalForm | null>(null)
  const [values, setValues] = useState<ProductTechnicalFormValues>({})
  const [isLoading, setIsLoading] = useState(false)
  const [isSaving, setIsSaving] = useState(false)
  const [error, setError] = useState('')
  const [infoMessage, setInfoMessage] = useState('')

  useEffect(() => {
    if (open) {
      setMounted(true)
      setClosing(false)
    } else if (mounted) {
      setClosing(true)
      const timer = setTimeout(() => {
        setMounted(false)
        setClosing(false)
      }, ANIMATION_MS)
      return () => clearTimeout(timer)
    }
  }, [open, mounted])

  useEffect(() => {
    if (!open || !productId) return

    const controller = new AbortController()
    void loadData(controller.signal)
    return () => controller.abort()
  }, [open, productId])

  async function loadData(signal?: AbortSignal) {
    setIsLoading(true)
    setError('')
    setInfoMessage('')

    try {
      const data = await getProductTechnicalInfo(productId, signal)
      setForm(data.form)
      setValues(valuesToFormState(data.form, data.values))
      if (data.message) {
        setInfoMessage(data.message)
      } else if (!categoryId) {
        setInfoMessage('Assign a category to this product before adding technical data.')
      } else if (!data.form) {
        setInfoMessage('No technical form is defined for this product category.')
      }
    } catch (err) {
      if (err instanceof DOMException && err.name === 'AbortError') return
      if (err instanceof ApiError) {
        setError(err.message)
      } else {
        setError('Unable to load technical data.')
      }
    } finally {
      setIsLoading(false)
    }
  }

  useEffect(() => {
    if (!mounted || closing) return
    const onKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape') onClose()
    }
    document.addEventListener('keydown', onKey)
    return () => document.removeEventListener('keydown', onKey)
  }, [mounted, closing, onClose])

  if (!mounted) return null

  function setFieldValue(fieldKey: string, value: string | string[]) {
    setValues((prev) => ({ ...prev, [fieldKey]: value }))
  }

  function toggleMultiOption(fieldKey: string, optionValue: string) {
    setValues((prev) => {
      const current = prev[fieldKey]
      const selected = Array.isArray(current) ? current : []
      const next = selected.includes(optionValue)
        ? selected.filter((item) => item !== optionValue)
        : [...selected, optionValue]
      return { ...prev, [fieldKey]: next }
    })
  }

  function isFormValid() {
    if (!form) return false

    return form.fields.every((field) => {
      if (!field.isRequired) return true
      const value = values[field.key]
      if (field.type === 'multi_select') {
        return Array.isArray(value) && value.length > 0
      }
      return typeof value === 'string' && value.trim().length > 0
    })
  }

  async function handleSave() {
    if (!form) return

    setIsSaving(true)
    setError('')

    try {
      const data = await saveProductTechnicalInfo(productId, values)
      setForm(data.form)
      setValues(valuesToFormState(data.form, data.values))
      onClose()
    } catch (err) {
      if (err instanceof ApiError) {
        setError(err.message)
      } else {
        setError('Unable to save technical data.')
      }
    } finally {
      setIsSaving(false)
    }
  }

  function renderField(field: CategoryTechnicalForm['fields'][number]) {
    const value = values[field.key]
    const type = field.type as TechnicalFieldType

    if (type === 'textarea') {
      return (
        <textarea
          id={`tech-${field.key}`}
          value={typeof value === 'string' ? value : ''}
          onChange={(e) => setFieldValue(field.key, e.target.value)}
        />
      )
    }

    if (type === 'select') {
      return (
        <select
          id={`tech-${field.key}`}
          value={typeof value === 'string' ? value : ''}
          onChange={(e) => setFieldValue(field.key, e.target.value)}
        >
          <option value="">Select...</option>
          {field.options.map((option) => (
            <option key={option.id} value={option.value}>
              {option.label}
            </option>
          ))}
        </select>
      )
    }

    if (type === 'multi_select') {
      const selected = Array.isArray(value) ? value : []
      return (
        <div className={styles.chipGrid}>
          {field.options.map((option) => (
            <button
              key={option.id}
              type="button"
              className={`${styles.chip} ${selected.includes(option.value) ? styles.chipSelected : ''}`}
              onClick={() => toggleMultiOption(field.key, option.value)}
            >
              {option.label}
            </button>
          ))}
        </div>
      )
    }

    return (
      <input
        id={`tech-${field.key}`}
        type="text"
        value={typeof value === 'string' ? value : ''}
        onChange={(e) => setFieldValue(field.key, e.target.value)}
      />
    )
  }

  return createPortal(
    <div
      className={`${styles.overlay} ${closing ? styles.overlayOut : styles.overlayIn}`}
      onClick={onClose}
    >
      <div
        className={`${styles.modal} ${fieldStyles.modalWide} ${closing ? styles.modalOut : styles.modalIn}`}
        onClick={(e) => e.stopPropagation()}
        role="dialog"
        aria-modal="true"
        aria-labelledby="product-technical-title"
      >
        <div className={styles.header}>
          <div>
            <h3 id="product-technical-title" className={styles.title}>
              Technical Data
            </h3>
            {productName && <p className={styles.subtitle}>{productName}</p>}
          </div>
          <button className={styles.closeBtn} onClick={onClose} aria-label="Close">
            <X size={20} />
          </button>
        </div>

        <div className={styles.body}>
          {isLoading ? (
            <p className={styles.emptyText}>Loading technical data...</p>
          ) : infoMessage && !form ? (
            <p className={styles.emptyText}>{infoMessage}</p>
          ) : form && form.fields.length === 0 ? (
            <p className={styles.emptyText}>This category form has no fields yet.</p>
          ) : (
            form?.fields.map((field) => (
              <div key={field.id} className={styles.field}>
                <label htmlFor={`tech-${field.key}`}>
                  {field.label}
                  {field.isRequired && ' *'}
                </label>
                {renderField(field)}
              </div>
            ))
          )}

          {error && <p className={styles.errorText}>{error}</p>}

          <div className={styles.actions}>
            <button type="button" className={styles.cancelBtn} onClick={onClose}>
              Cancel
            </button>
            <button
              type="button"
              className={styles.submitBtn}
              onClick={() => void handleSave()}
              disabled={!form || !isFormValid() || isSaving || isLoading}
            >
              {isSaving ? 'Saving…' : 'Save'}
            </button>
          </div>
        </div>
      </div>
    </div>
  ,
  document.body,
  )
}
