import {
  createContext,
  useCallback,
  useContext,
  useMemo,
  useState,
  type ReactNode,
} from 'react'
import type { BusinessCustomer } from '../services/customerService'
import type { ShoppingCard } from '../services/shoppingCardService'
import type { StoreItem } from '../services/storeItemService'
import {
  draftCartItemCount,
  draftCartSubtotal,
  shoppingCardCustomerToBusinessCustomer,
  shoppingCardToDraftItems,
  storeItemToDraftCartItem,
  RESUME_SHOPPING_CARD_KEY,
  type DraftCartItem,
} from '../types/draftCart'

interface DraftCartContextValue {
  items: DraftCartItem[]
  customer: BusinessCustomer | null
  resumedShoppingCardId: string | null
  itemCount: number
  subtotal: number
  hasItems: boolean
  addVariant: (variant: StoreItem, quantity?: number) => string | null
  updateQuantity: (storeItemVariantId: string, quantity: number) => void
  removeItem: (storeItemVariantId: string) => void
  setCustomer: (customer: BusinessCustomer | null) => void
  loadShoppingCard: (card: ShoppingCard) => void
  clear: () => void
  clearAll: () => void
}

const DraftCartContext = createContext<DraftCartContextValue | null>(null)

export function DraftCartProvider({ children }: { children: ReactNode }) {
  const [items, setItems] = useState<DraftCartItem[]>([])
  const [customer, setCustomer] = useState<BusinessCustomer | null>(null)
  const [resumedShoppingCardId, setResumedShoppingCardId] = useState<string | null>(null)

  const addVariant = useCallback((variant: StoreItem, quantity = 1) => {
    const draft = storeItemToDraftCartItem(variant, quantity)
    if (!draft) {
      return 'This variant has no price configured.'
    }

    if (draft.stockQuantity !== null && quantity > draft.stockQuantity) {
      return `Only ${draft.stockQuantity} in stock.`
    }

    let error: string | null = null

    setItems((prev) => {
      const existing = prev.find(
        (item) => item.storeItemVariantId === draft.storeItemVariantId,
      )

      if (existing) {
        const newQuantity = existing.quantity + quantity
        if (
          existing.stockQuantity !== null &&
          newQuantity > existing.stockQuantity
        ) {
          error = `Only ${existing.stockQuantity} in stock.`
          return prev
        }

        return prev.map((item) =>
          item.storeItemVariantId === draft.storeItemVariantId
            ? { ...item, quantity: newQuantity }
            : item,
        )
      }

      return [...prev, draft]
    })

    return error
  }, [])

  const updateQuantity = useCallback((storeItemVariantId: string, quantity: number) => {
    if (quantity < 1) {
      setItems((prev) =>
        prev.filter((item) => item.storeItemVariantId !== storeItemVariantId),
      )
      return
    }

    setItems((prev) =>
      prev.map((item) => {
        if (item.storeItemVariantId !== storeItemVariantId) return item
        if (item.stockQuantity !== null && quantity > item.stockQuantity) {
          return item
        }
        return { ...item, quantity }
      }),
    )
  }, [])

  const removeItem = useCallback((storeItemVariantId: string) => {
    setItems((prev) =>
      prev.filter((item) => item.storeItemVariantId !== storeItemVariantId),
    )
  }, [])

  const clear = useCallback(() => {
    setItems([])
  }, [])

  const clearAll = useCallback(() => {
    setItems([])
    setCustomer(null)
    setResumedShoppingCardId(null)
    sessionStorage.removeItem(RESUME_SHOPPING_CARD_KEY)
  }, [])

  const loadShoppingCard = useCallback((card: ShoppingCard) => {
    setCustomer(shoppingCardCustomerToBusinessCustomer(card.customer))
    setItems(shoppingCardToDraftItems(card))
    setResumedShoppingCardId(card.id)
  }, [])

  const value = useMemo<DraftCartContextValue>(
    () => ({
      items,
      customer,
      resumedShoppingCardId,
      itemCount: draftCartItemCount(items),
      subtotal: draftCartSubtotal(items),
      hasItems: items.length > 0,
      addVariant,
      updateQuantity,
      removeItem,
      setCustomer,
      loadShoppingCard,
      clear,
      clearAll,
    }),
    [
      items,
      customer,
      resumedShoppingCardId,
      addVariant,
      updateQuantity,
      removeItem,
      loadShoppingCard,
      clear,
      clearAll,
    ],
  )

  return (
    <DraftCartContext.Provider value={value}>{children}</DraftCartContext.Provider>
  )
}

export function useDraftCart() {
  const context = useContext(DraftCartContext)
  if (!context) {
    throw new Error('useDraftCart must be used within DraftCartProvider')
  }
  return context
}
