import { useEffect, useMemo, useState } from 'react'
import { createPortal } from 'react-dom'
import { Plus, X } from 'lucide-react'
import { ApiError } from '../lib/api'
import { listAllProducts } from '../services/productService'
import {
  getProductVariationValues,
  type ProductVariationSelection,
} from '../services/productVariationService'
import {
  batchCreateStoreItems,
  type CreateStoreItemPayload,
} from '../services/storeItemService'
import { createId } from '../utils/id'
import { formatIrtInput, parseIrtInput } from '../utils/irtPrice'
import {
  createEmptyStoreItemRow,
  getVariationOptions,
  type StoreItemDraftRow,
} from '../utils/storeItemRows'
import { ProductSearchSelect } from './ProductSearchSelect'
import { Tooltip } from './Tooltip'
import modalStyles from './VariationsModal.module.css'
import rowStyles from './CreateStoreItemsModal.module.css'

interface CreateStoreItemsModalProps {
  open: boolean
  existingProductIds: string[]
  onClose: () => void
  onCreated?: () => void
  onEditExisting?: (productId: string) => void
}

const ANIMATION_MS = 220

export function CreateStoreItemsModal({
  open,
  existingProductIds,
  onClose,
  onCreated,
  onEditExisting,
}: CreateStoreItemsModalProps) {
  const [mounted, setMounted] = useState(open)
  const [closing, setClosing] = useState(false)
  const [products, setProducts] = useState<{ id: string; title: string; nameFa: string }[]>([])
  const [productId, setProductId] = useState('')
  const [variations, setVariations] = useState<ProductVariationSelection[]>([])
  const [rows, setRows] = useState<StoreItemDraftRow[]>([])
  const [isLoadingProducts, setIsLoadingProducts] = useState(false)
  const [isLoadingVariations, setIsLoadingVariations] = useState(false)
  const [isSubmitting, setIsSubmitting] = useState(false)
  const [error, setError] = useState('')

  const formVariations = useMemo(
    () => variations.filter((variation) => getVariationOptions(variation).length > 0),
    [variations],
  )

  const gridTemplate = useMemo(() => {
    const variationCols = formVariations.map(() => 'minmax(110px, 1fr)').join(' ')
    const cols = [variationCols, 'minmax(120px, 1fr)', '90px', '32px'].filter((part) => part).join(' ')
    return cols || 'minmax(120px, 1fr) 90px 32px'
  }, [formVariations])

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

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

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

  useEffect(() => {
    if (!productId) {
      setVariations([])
      setRows([])
      return
    }

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

  async function loadProducts(signal?: AbortSignal) {
    setIsLoadingProducts(true)
    setError('')

    try {
      const items = await listAllProducts(signal)
      setProducts(
        items.map((item) => ({
          id: item.id,
          title: item.title,
          nameFa: item.nameFa,
        })),
      )
    } catch (err) {
      if (err instanceof DOMException && err.name === 'AbortError') return
      if (err instanceof ApiError) {
        setError(err.message)
      } else {
        setError('Unable to load products.')
      }
    } finally {
      setIsLoadingProducts(false)
    }
  }

  async function loadVariations(nextProductId: string, signal?: AbortSignal) {
    setIsLoadingVariations(true)
    setError('')

    try {
      const data = await getProductVariationValues(nextProductId, signal)
      setVariations(data.variations)
      setRows([createEmptyStoreItemRow()])
    } catch (err) {
      if (err instanceof DOMException && err.name === 'AbortError') return
      if (err instanceof ApiError) {
        setError(err.message)
      } else {
        setError('Unable to load product variations.')
      }
      setVariations([])
      setRows([])
    } finally {
      setIsLoadingVariations(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 handleProductChange(nextProductId: string) {
    if (nextProductId && existingProductIds.includes(nextProductId)) {
      onEditExisting?.(nextProductId)
      onClose()
      return
    }
    setProductId(nextProductId)
  }

  function updateRow(rowId: string, patch: Partial<StoreItemDraftRow>) {
    setRows((prev) => prev.map((row) => (row.id === rowId ? { ...row, ...patch } : row)))
  }

  function updateRowSelection(rowId: string, variationId: string, optionId: string) {
    setRows((prev) =>
      prev.map((row) => {
        if (row.id !== rowId) return row
        const nextSelections = { ...row.selections }
        if (!optionId) {
          delete nextSelections[variationId]
        } else {
          nextSelections[variationId] = optionId
        }
        return { ...row, selections: nextSelections }
      }),
    )
  }

  function addRow() {
    setRows((prev) => [...prev, { ...createEmptyStoreItemRow(), id: createId() }])
  }

  function removeRow(rowId: string) {
    setRows((prev) => (prev.length <= 1 ? prev : prev.filter((row) => row.id !== rowId)))
  }

  function buildPayload(): CreateStoreItemPayload[] {
    return rows.map((row) => ({
      selections: formVariations.flatMap((variation) => {
        const optionId = row.selections[variation.id]
        if (!optionId) return []
        return [{ variationId: variation.id, optionId }]
      }),
      price: parseIrtInput(row.price) ?? undefined,
      stockQuantity: row.stock.trim() ? Number(row.stock) : undefined,
    }))
  }

  const canSubmit =
    Boolean(productId) &&
    rows.length > 0 &&
    rows.every((row) => {
      const price = parseIrtInput(row.price)
      const stock = Number(row.stock)
      return price !== null && price >= 0 && row.stock.trim() !== '' && !Number.isNaN(stock) && stock >= 0
    }) &&
    !isSubmitting &&
    !isLoadingVariations

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault()
    if (!canSubmit) return

    setIsSubmitting(true)
    setError('')

    try {
      await batchCreateStoreItems({
        productId,
        items: buildPayload(),
      })
      onCreated?.()
      onClose()
    } catch (err) {
      if (err instanceof ApiError) {
        setError(err.message)
      } else {
        setError('Unable to create store items.')
      }
    } finally {
      setIsSubmitting(false)
    }
  }

  return createPortal(
    <div
      className={`${modalStyles.overlay} ${closing ? modalStyles.overlayOut : modalStyles.overlayIn}`}
      onClick={onClose}
    >
      <div
        className={`${modalStyles.modal} ${rowStyles.modalWide} ${closing ? modalStyles.modalOut : modalStyles.modalIn}`}
        onClick={(e) => e.stopPropagation()}
        role="dialog"
        aria-modal="true"
        aria-labelledby="create-store-items-title"
      >
        <div className={modalStyles.header}>
          <div>
            <h3 id="create-store-items-title" className={modalStyles.title}>
              Add Store Items
            </h3>
            <p className={modalStyles.subtitle}>
              Create sellable variants from a product&apos;s variations.
            </p>
          </div>
          <button className={modalStyles.closeBtn} onClick={onClose} aria-label="Close">
            <X size={20} />
          </button>
        </div>

        <form className={modalStyles.body} onSubmit={(e) => void handleSubmit(e)}>
          <div className={modalStyles.field}>
            <label htmlFor="store-item-product">Product</label>
            <ProductSearchSelect
              id="store-item-product"
              options={products}
              value={productId}
              onChange={handleProductChange}
              placeholder="Type 3+ characters to search products"
              disabled={isLoadingProducts || isSubmitting}
            />
          </div>

          {productId && isLoadingVariations && (
            <p className={modalStyles.emptyText}>Loading product variations...</p>
          )}

          {productId && !isLoadingVariations && (
            <>
              <div
                className={rowStyles.itemRowHeader}
                style={{ gridTemplateColumns: gridTemplate }}
              >
                {formVariations.map((variation) => (
                  <span key={variation.id}>{variation.name}</span>
                ))}
                <span>Price (IRT)</span>
                <span>Stock</span>
                <span />
              </div>

              <div className={rowStyles.itemRows}>
                {rows.map((row) => (
                  <div
                    key={row.id}
                    className={rowStyles.itemRow}
                    style={{ gridTemplateColumns: gridTemplate }}
                  >
                    {formVariations.map((variation) => {
                      const options = getVariationOptions(variation)
                      return (
                        <select
                          key={variation.id}
                          className={rowStyles.compactInput}
                          value={row.selections[variation.id] ?? ''}
                          onChange={(e) =>
                            updateRowSelection(row.id, variation.id, e.target.value)
                          }
                          disabled={isSubmitting}
                        >
                          <option value="">—</option>
                          {options.map((option) => (
                            <option key={option.id} value={option.id}>
                              {option.label}
                            </option>
                          ))}
                        </select>
                      )
                    })}
                    <input
                      type="text"
                      inputMode="numeric"
                      className={rowStyles.compactInput}
                      value={row.price}
                      onChange={(e) => updateRow(row.id, { price: formatIrtInput(e.target.value) })}
                      placeholder="0"
                      disabled={isSubmitting}
                    />
                    <input
                      type="number"
                      min="0"
                      step="1"
                      className={rowStyles.compactInput}
                      value={row.stock}
                      onChange={(e) => updateRow(row.id, { stock: e.target.value })}
                      disabled={isSubmitting}
                    />
                    <div className={rowStyles.removeCell}>
                      <Tooltip label="Remove row">
                        <button
                          type="button"
                          className={modalStyles.removeRowBtn}
                          onClick={() => removeRow(row.id)}
                          disabled={rows.length <= 1 || isSubmitting}
                          aria-label="Remove row"
                        >
                          <X size={16} />
                        </button>
                      </Tooltip>
                    </div>
                  </div>
                ))}
              </div>

              <button
                type="button"
                className={rowStyles.addRowBtn}
                onClick={addRow}
                disabled={isSubmitting}
              >
                <Plus size={16} />
                Add row
              </button>
            </>
          )}

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

          <div className={modalStyles.actions}>
            <button
              type="button"
              className={modalStyles.cancelBtn}
              onClick={onClose}
              disabled={isSubmitting}
            >
              Cancel
            </button>
            <button
              type="submit"
              className={modalStyles.submitBtn}
              disabled={!canSubmit}
            >
              {isSubmitting ? 'Creating…' : 'Create store items'}
            </button>
          </div>
        </form>
      </div>
    </div>
  ,
  document.body,
  )
}
