import { useEffect, useMemo, useRef, useState } from 'react'
import { createPortal } from 'react-dom'
import { ArrowLeft, Minus, Plus, Search, Trash2, User, X } from 'lucide-react'
import { useDraftCart } from '../context/DraftCartContext'
import { useToast } from '../context/ToastContext'
import { ApiError } from '../lib/api'
import {
  searchCustomers,
  type BusinessCustomer,
} from '../services/customerService'
import { createAdminOrder } from '../services/orderService'
import { createShoppingCard, removeShoppingCard } from '../services/shoppingCardService'
import { createId } from '../utils/id'
import { formatIrtInput, formatIrtPrice, parseIrtInput } from '../utils/irtPrice'
import { Tooltip } from './Tooltip'
import rowStyles from './CreateStoreItemsModal.module.css'
import modalStyles from './VariationsModal.module.css'
import removeStyles from './VariationsModal.module.css'
import styles from './ShoppingCartModal.module.css'

interface ShoppingCartModalProps {
  open: boolean
  onClose: () => void
  onOrderCreated?: () => void
}

type ModalStep = 'cart' | 'payment'

export type OrderPaymentMethod = 'pos' | 'cash' | 'transfer'

interface PaymentRow {
  id: string
  method: OrderPaymentMethod
  amountInput: string
  accountNumber: string
  refCode: string
}

const ANIMATION_MS = 220
const SEARCH_DEBOUNCE_MS = 300

const PAYMENT_METHOD_OPTIONS: { value: OrderPaymentMethod; label: string }[] = [
  { value: 'pos', label: 'POS' },
  { value: 'cash', label: 'Cash' },
  { value: 'transfer', label: 'Transfer' },
]

function resetCustomerSelection(
  setQuery: (value: string) => void,
  setCustomers: (value: BusinessCustomer[]) => void,
  setSelectedCustomer: (value: BusinessCustomer | null) => void,
) {
  setQuery('')
  setCustomers([])
  setSelectedCustomer(null)
}

function createDefaultPayments(orderTotal: number): PaymentRow[] {
  return [
    {
      id: createId(),
      method: 'pos',
      amountInput: formatIrtInput(String(Math.round(orderTotal))),
      accountNumber: '',
      refCode: '',
    },
  ]
}

function paymentRowsTotal(rows: PaymentRow[]) {
  return rows.reduce((sum, row) => sum + (parseIrtInput(row.amountInput) ?? 0), 0)
}

function paymentsAreValid(rows: PaymentRow[], orderTotal: number) {
  if (paymentRowsTotal(rows) !== orderTotal) return false
  return rows.every((row) => {
    if (row.method !== 'transfer') return true
    return Boolean(row.accountNumber.trim() && row.refCode.trim())
  })
}

function buildOrderPayments(rows: PaymentRow[]) {
  return rows.map((row) => {
    const amount = parseIrtInput(row.amountInput) ?? 0
    if (row.method === 'transfer') {
      return {
        type: 'transfer' as const,
        amount,
        transferAccount: row.accountNumber.trim(),
        transferRefNumber: row.refCode.trim(),
      }
    }
    if (row.method === 'pos') {
      return {
        type: 'pos' as const,
        amount,
        posType: 'operator',
      }
    }
    return {
      type: row.method,
      amount,
    }
  })
}

export function ShoppingCartModal({ open, onClose, onOrderCreated }: ShoppingCartModalProps) {
  const { showToast } = useToast()
  const {
    items,
    itemCount,
    subtotal,
    customer,
    setCustomer,
    resumedShoppingCardId,
    updateQuantity,
    removeItem,
    clearAll,
  } = useDraftCart()
  const [mounted, setMounted] = useState(open)
  const [closing, setClosing] = useState(false)
  const [step, setStep] = useState<ModalStep>('cart')
  const [query, setQuery] = useState('')
  const [customers, setCustomers] = useState<BusinessCustomer[]>([])
  const [payments, setPayments] = useState<PaymentRow[]>([])
  const [isSearching, setIsSearching] = useState(false)
  const [isSubmitting, setIsSubmitting] = useState(false)
  const [error, setError] = useState('')
  const searchSeq = useRef(0)

  const canProceed = Boolean(customer && items.length > 0)
  const paymentAllocated = useMemo(() => paymentRowsTotal(payments), [payments])
  const paymentRemaining = subtotal - paymentAllocated
  const paymentsBalanced = payments.length > 0 && paymentRemaining === 0
  const paymentsValid = paymentsAreValid(payments, subtotal)

  useEffect(() => {
    if (open) {
      setMounted(true)
      setClosing(false)
      setStep('cart')
      setPayments([])
      setError('')
      setQuery(customer?.label ?? '')
      setCustomers([])
    } else if (mounted) {
      setClosing(true)
      const timer = setTimeout(() => {
        setMounted(false)
        setClosing(false)
        setStep('cart')
        setPayments([])
        setQuery(customer?.label ?? '')
        setCustomers([])
        setError('')
      }, ANIMATION_MS)
      return () => clearTimeout(timer)
    }
  }, [open, mounted, customer?.label])

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

  useEffect(() => {
    const trimmed = query.trim()
    if (trimmed.length < 2) {
      setCustomers([])
      setIsSearching(false)
      return
    }

    const seq = ++searchSeq.current
    setIsSearching(true)
    const timer = setTimeout(() => {
      void (async () => {
        try {
          const result = await searchCustomers(trimmed)
          if (seq !== searchSeq.current) return
          setCustomers(result.items)
        } catch (err) {
          if (seq !== searchSeq.current) return
          if (err instanceof ApiError) {
            setError(err.message)
          }
        } finally {
          if (seq === searchSeq.current) {
            setIsSearching(false)
          }
        }
      })()
    }, SEARCH_DEBOUNCE_MS)

    return () => clearTimeout(timer)
  }, [query])

  async function handleSaveAndStartNew() {
    if (!customer || !items.length) return

    setIsSubmitting(true)
    setError('')

    try {
      await createShoppingCard({
        customerUserId: customer.id,
        items: items.map((item) => ({
          storeItemVariantId: item.storeItemVariantId,
          quantity: item.quantity,
        })),
      })
      clearAll()
      resetCustomerSelection(setQuery, setCustomers, setCustomer)
      setStep('cart')
      setPayments([])
      onClose()
      showToast('Shopping card saved.', 'success')
    } catch (err) {
      if (err instanceof ApiError) {
        setError(err.message)
      } else {
        setError('Unable to save shopping card.')
      }
    } finally {
      setIsSubmitting(false)
    }
  }

  function handleProceedWithPayment() {
    if (!canProceed) return
    setError('')
    setPayments(createDefaultPayments(subtotal))
    setStep('payment')
  }

  function handleBackToCart() {
    setStep('cart')
    setError('')
  }

  function updatePaymentRow(id: string, patch: Partial<PaymentRow>) {
    setPayments((prev) => prev.map((row) => (row.id === id ? { ...row, ...patch } : row)))
  }

  function addPaymentRow() {
    setPayments((prev) => {
      const used = new Set(prev.map((row) => row.method))
      const nextMethod = PAYMENT_METHOD_OPTIONS.find((option) => !used.has(option.value))?.value
      if (!nextMethod) return prev

      const allocated = paymentRowsTotal(prev)
      const remaining = Math.max(0, subtotal - allocated)

      return [
        ...prev,
        {
          id: createId(),
          method: nextMethod,
          amountInput: remaining > 0 ? formatIrtInput(String(remaining)) : '',
          accountNumber: '',
          refCode: '',
        },
      ]
    })
  }

  function removePaymentRow(id: string) {
    setPayments((prev) => {
      if (prev.length <= 1) return prev
      return prev.filter((row) => row.id !== id)
    })
  }

  async function handleConfirmPayment() {
    if (!customer) return

    if (!paymentsBalanced) {
      setError('Payment amounts must equal the order total.')
      return
    }

    const missingTransferDetails = payments.some(
      (row) =>
        row.method === 'transfer' && (!row.accountNumber.trim() || !row.refCode.trim()),
    )
    if (missingTransferDetails) {
      setError('Account number and ref code are required for transfer payments.')
      return
    }

    setIsSubmitting(true)
    setError('')

    try {
      const result = await createAdminOrder({
        customerUserId: customer.id,
        items: items.map((item) => ({
          storeItemVariantId: item.storeItemVariantId,
          quantity: item.quantity,
        })),
        status: 'pending',
        payments: buildOrderPayments(payments),
      })

      if (resumedShoppingCardId) {
        try {
          await removeShoppingCard(resumedShoppingCardId)
        } catch {
          // Order was created; card removal is best-effort.
        }
      }

      showToast(`Order ${result.order.orderNumber} saved successfully.`, 'success')
      clearAll()
      resetCustomerSelection(setQuery, setCustomers, setCustomer)
      setStep('cart')
      setPayments([])
      onOrderCreated?.()
      onClose()
    } catch (err) {
      if (err instanceof ApiError) {
        setError(err.message)
      } else {
        setError('Unable to save order.')
      }
    } finally {
      setIsSubmitting(false)
    }
  }

  if (!mounted) return null

  const canAddPayment = payments.length < PAYMENT_METHOD_OPTIONS.length

  return createPortal(
    <div
      className={`${modalStyles.overlay} ${closing ? modalStyles.overlayOut : modalStyles.overlayIn}`}
      onClick={onClose}
    >
      <div
        className={`${modalStyles.modal} ${styles.modalWide} ${closing ? modalStyles.modalOut : modalStyles.modalIn}`}
        onClick={(e) => e.stopPropagation()}
        role="dialog"
        aria-modal="true"
        aria-labelledby="shopping-cart-title"
      >
        <div className={modalStyles.header}>
          <div>
            {step === 'payment' && (
              <button type="button" className={styles.backBtn} onClick={handleBackToCart}>
                <ArrowLeft size={14} />
                Back to cart
              </button>
            )}
            <h2 id="shopping-cart-title" className={modalStyles.title}>
              {step === 'payment' ? 'Payment' : 'Shopping cart'}
            </h2>
            {step === 'payment' && customer && (
              <p className={modalStyles.subtitle}>{customer.label}</p>
            )}
          </div>
          <button type="button" className={modalStyles.closeBtn} onClick={onClose} aria-label="Close">
            <X size={18} />
          </button>
        </div>

        <div className={`${modalStyles.body} ${styles.body}`}>
          {step === 'cart' ? (
            <>
              <section className={styles.section}>
                <h3 className={styles.sectionTitle}>Items</h3>
                {items.length === 0 ? (
                  <p className={styles.empty}>Your cart is empty.</p>
                ) : (
                  <>
                    <ul className={styles.itemList}>
                      {items.map((item) => (
                        <li key={item.storeItemVariantId} className={styles.itemRow}>
                          <div className={styles.itemThumb}>
                            {item.productImage ? (
                              <img src={item.productImage} alt="" />
                            ) : (
                              <div className={styles.itemThumbPlaceholder} />
                            )}
                          </div>
                          <div className={styles.itemInfo}>
                            <div className={styles.itemTitle}>{item.productTitle}</div>
                            {item.productNameFa && (
                              <div className={`${styles.itemFa} faText`}>{item.productNameFa}</div>
                            )}
                            <div className={styles.itemVariant}>{item.label}</div>
                          </div>
                          <div className={styles.itemPriceCol}>
                            <span className={styles.itemPrice}>
                              {formatIrtPrice(item.unitPrice * item.quantity)}
                            </span>
                          </div>
                          <div className={styles.itemActions}>
                            <div className={styles.qtyControls}>
                              <Tooltip label="Decrease quantity">
                                <button
                                  type="button"
                                  className={styles.qtyBtn}
                                  onClick={() =>
                                    updateQuantity(item.storeItemVariantId, item.quantity - 1)
                                  }
                                  aria-label="Decrease quantity"
                                >
                                  <Minus size={14} />
                                </button>
                              </Tooltip>
                              <span className={styles.qtyValue}>{item.quantity}</span>
                              <Tooltip label="Increase quantity">
                                <button
                                  type="button"
                                  className={styles.qtyBtn}
                                  onClick={() =>
                                    updateQuantity(item.storeItemVariantId, item.quantity + 1)
                                  }
                                  disabled={
                                    item.stockQuantity !== null &&
                                    item.quantity >= item.stockQuantity
                                  }
                                  aria-label="Increase quantity"
                                >
                                  <Plus size={14} />
                                </button>
                              </Tooltip>
                            </div>
                            <Tooltip label="Remove item">
                              <button
                                type="button"
                                className={removeStyles.removeRowBtn}
                                onClick={() => removeItem(item.storeItemVariantId)}
                                aria-label="Remove item"
                              >
                                <Trash2 size={16} />
                              </button>
                            </Tooltip>
                          </div>
                        </li>
                      ))}
                    </ul>
                    <div className={styles.itemsTotal}>
                      <span className={styles.itemsTotalLabel}>
                        Total · {itemCount} {itemCount === 1 ? 'item' : 'items'}
                      </span>
                      <span className={styles.itemsTotalPrice}>{formatIrtPrice(subtotal)}</span>
                    </div>
                  </>
                )}
              </section>

              <section className={styles.section}>
                <h3 className={styles.sectionTitle}>Assign customer</h3>
                <p className={styles.sectionHint}>
                  Search by name, phone, or email. A customer must be selected before you can save
                  or proceed with payment.
                </p>
                <div className={styles.searchWrap}>
                  <Search size={16} className={styles.searchIcon} />
                  <input
                    type="text"
                    className={styles.searchInput}
                    placeholder="Search customers..."
                    value={query}
                    onChange={(e) => {
                      setQuery(e.target.value)
                      setCustomer(null)
                    }}
                  />
                </div>

                {customer && (
                  <div className={styles.selectedCustomer}>
                    <User size={16} />
                    <span>{customer.label}</span>
                    <button
                      type="button"
                      className={styles.clearCustomerBtn}
                      onClick={() => {
                        setCustomer(null)
                        setQuery('')
                      }}
                      aria-label="Clear customer"
                    >
                      <X size={14} />
                    </button>
                  </div>
                )}

                {!customer && query.trim().length >= 2 && (
                  <ul className={styles.customerList}>
                    {isSearching ? (
                      <li className={styles.customerEmpty}>Searching...</li>
                    ) : customers.length === 0 ? (
                      <li className={styles.customerEmpty}>No customers found.</li>
                    ) : (
                      customers.map((option) => (
                        <li key={option.id}>
                          <button
                            type="button"
                            className={styles.customerOption}
                            onClick={() => {
                              setCustomer(option)
                              setQuery(option.label)
                              setCustomers([])
                            }}
                          >
                            <User size={16} />
                            <span>{option.label}</span>
                          </button>
                        </li>
                      ))
                    )}
                  </ul>
                )}
              </section>

              <div className={styles.cartActions}>
                <button type="button" className={modalStyles.cancelBtn} onClick={onClose}>
                  Close
                </button>
                <button
                  type="button"
                  className={styles.secondaryBtn}
                  onClick={() => void handleSaveAndStartNew()}
                  disabled={!canProceed || isSubmitting}
                >
                  {isSubmitting ? 'Saving...' : 'Save and start new one'}
                </button>
                <button
                  type="button"
                  className={modalStyles.submitBtn}
                  onClick={handleProceedWithPayment}
                  disabled={!canProceed}
                >
                  Proceed with payment
                </button>
              </div>
            </>
          ) : (
            <>
              <section className={styles.section}>
                <h3 className={styles.sectionTitle}>Payment methods</h3>
                <p className={styles.sectionHint}>
                  Split the order total across one or more payment methods. The allocated amount must
                  match the order total exactly.
                </p>

                <div className={styles.paymentSummary}>
                  <span>
                    Order total: <strong>{formatIrtPrice(subtotal)}</strong>
                  </span>
                  <span>
                    Allocated: <strong>{formatIrtPrice(paymentAllocated)}</strong>
                  </span>
                  <span
                    className={
                      paymentsBalanced ? styles.paymentSummaryBalanced : styles.paymentSummaryUnbalanced
                    }
                  >
                    Remaining: <strong>{formatIrtPrice(paymentRemaining)}</strong>
                  </span>
                </div>

                <div className={styles.paymentDuplicator}>
                  <div className={styles.paymentGridHeader}>
                    <span>Payment method</span>
                    <span>Account number / Ref code</span>
                    <span>Amount (IRT)</span>
                    <span />
                  </div>

                  {payments.map((row) => {
                    const usedMethods = new Set(
                      payments.filter((payment) => payment.id !== row.id).map((payment) => payment.method),
                    )

                    return (
                      <div key={row.id} className={styles.paymentGridRow}>
                        <select
                          value={row.method}
                          onChange={(e) => {
                            const method = e.target.value as OrderPaymentMethod
                            updatePaymentRow(row.id, {
                              method,
                              accountNumber: method === 'transfer' ? row.accountNumber : '',
                              refCode: method === 'transfer' ? row.refCode : '',
                            })
                          }}
                        >
                          {PAYMENT_METHOD_OPTIONS.map((option) => (
                            <option
                              key={option.value}
                              value={option.value}
                              disabled={usedMethods.has(option.value)}
                            >
                              {option.label}
                            </option>
                          ))}
                        </select>

                        <div className={styles.paymentDetailsCell}>
                          {row.method === 'transfer' && (
                            <div className={styles.transferFieldsInline}>
                              <input
                                type="text"
                                value={row.accountNumber}
                                onChange={(e) =>
                                  updatePaymentRow(row.id, { accountNumber: e.target.value })
                                }
                                placeholder="Account number"
                                autoComplete="off"
                                aria-label="Account number"
                              />
                              <input
                                type="text"
                                value={row.refCode}
                                onChange={(e) =>
                                  updatePaymentRow(row.id, { refCode: e.target.value })
                                }
                                placeholder="Ref code"
                                autoComplete="off"
                                aria-label="Ref code"
                              />
                            </div>
                          )}
                        </div>

                        <div className={styles.paymentAmountCell}>
                          <input
                            type="text"
                            inputMode="numeric"
                            value={row.amountInput}
                            onChange={(e) =>
                              updatePaymentRow(row.id, { amountInput: formatIrtInput(e.target.value) })
                            }
                            placeholder="0"
                            autoComplete="off"
                            aria-label="Amount in IRT"
                          />
                        </div>

                        <div className={styles.removeCell}>
                          <Tooltip label="Remove payment method">
                            <button
                              type="button"
                              className={removeStyles.removeRowBtn}
                              onClick={() => removePaymentRow(row.id)}
                              disabled={payments.length <= 1}
                              aria-label="Remove payment method"
                            >
                              <Trash2 size={16} />
                            </button>
                          </Tooltip>
                        </div>
                      </div>
                    )
                  })}
                </div>

                <button
                  type="button"
                  className={rowStyles.addRowBtn}
                  onClick={addPaymentRow}
                  disabled={!canAddPayment}
                >
                  <Plus size={16} />
                  Add payment method
                </button>
              </section>

              <div className={styles.cartActions}>
                <button type="button" className={modalStyles.cancelBtn} onClick={handleBackToCart}>
                  Back
                </button>
                <button
                  type="button"
                  className={modalStyles.submitBtn}
                  onClick={() => void handleConfirmPayment()}
                  disabled={!paymentsValid || isSubmitting}
                >
                  {isSubmitting ? 'Saving order...' : 'Confirm payment'}
                </button>
              </div>
            </>
          )}

          {error && <p className={styles.error}>{error}</p>}
        </div>
      </div>
    </div>
  ,
  document.body,
  )
}
