'use client'

import { useEffect, useState, useCallback, useRef } from 'react'
import { useRouter } from 'next/navigation'
import {
  ArrowLeft, Search, Plus, Minus, Trash2, ShoppingCart,
  Receipt, Loader2, X, User, UtensilsCrossed, Bell, BellRing,
  CreditCard, Wallet, HandCoins, CheckCircle2, WifiOff, Printer,
  QrCode, Building2, Copy, Clock, ShoppingBag, Tag
} from 'lucide-react'
import { formatCurrency } from '@/lib/utils'
import { QRCodeSVG } from 'qrcode.react'
import toast from 'react-hot-toast'
import { useSSE } from '@/hooks/useSSE'
import { useBrowserNotification } from '@/hooks/useBrowserNotification'
import { printReceipt, orderToReceiptData, ThermalPrintOptions, extractReceiptTemplate } from '@/lib/print-receipt'
import { isMenuAvailableNow } from '@/lib/schedule-utils'
import { buildTestReceipt } from '@/lib/thermal-receipt'
import { useThermalPrinter } from '@/hooks/useThermalPrinter'
import { useAuthStore } from '@/store/auth-store'
import { useFeatureGuard } from '@/hooks/useFeatureGuard'
import FeatureBlockedPage from '@/components/FeatureBlockedPage'
import { useOnlineStatus } from '@/hooks/useOnlineStatus'
import { useOfflineSync } from '@/hooks/useOfflineSync'
import { cachePOSData, getCachedPOSData, addOfflineOrder, getOfflineOrderCount } from '@/lib/offline-db'

interface SelectedVariant {
  variantId: string
  groupName: string
  name: string
  priceAdjustment: number
}

interface CartItem {
  cartKey: string
  menuItemId: string
  name: string
  price: number
  quantity: number
  notes: string
  selectedVariants: SelectedVariant[]
}

export default function POSPage() {
  const router = useRouter()
  const { allowed: featureAllowed, loading: featureLoading } = useFeatureGuard('pos')
  const [categories, setCategories] = useState<any[]>([])
  const [menuItems, setMenuItems] = useState<any[]>([])
  const [stores, setStores] = useState<any[]>([])
  const [tables, setTables] = useState<any[]>([])
  const [selectedStore, setSelectedStore] = useState('')
  const [selectedCategory, setSelectedCategory] = useState('')
  const [search, setSearch] = useState('')
  const [cart, setCart] = useState<CartItem[]>([])
  const [orderType, setOrderType] = useState('dine_in')
  const [selectedTable, setSelectedTable] = useState('')
  const [customerName, setCustomerName] = useState('')
  const [customerPhone, setCustomerPhone] = useState('')
  const [customerSuggestions, setCustomerSuggestions] = useState<any[]>([])
  const [showSuggestions, setShowSuggestions] = useState(false)
  const [selectedCustomerId, setSelectedCustomerId] = useState<string | null>(null)
  const [loyaltyInfo, setLoyaltyInfo] = useState<any>(null)
  const [loyaltyPointsToRedeem, setLoyaltyPointsToRedeem] = useState(0)
  const [loyaltyDiscount, setLoyaltyDiscount] = useState(0)
  const [showLoyaltyModal, setShowLoyaltyModal] = useState(false)
  const [notes, setNotes] = useState('')
  const [loading, setLoading] = useState(true)
  const [submitting, setSubmitting] = useState(false)
  const [showCheckout, setShowCheckout] = useState(false)

  // Variant selection state
  const [showVariantSelect, setShowVariantSelect] = useState(false)
  const [variantSelectItem, setVariantSelectItem] = useState<any>(null)
  const [variantSelections, setVariantSelections] = useState<Record<string, string[]>>({})

  // Notification panel
  const [notifications, setNotifications] = useState<any[]>([])
  const [showNotifications, setShowNotifications] = useState(false)
  const [lastNotifCount, setLastNotifCount] = useState(0)
  const { permission: notifPermission, requestPermission, notify } = useBrowserNotification()

  // Pending payment orders (from QR scan orders wanting to pay at cashier)
  const [paymentOrders, setPaymentOrders] = useState<any[]>([])
  const [showPaymentOrders, setShowPaymentOrders] = useState(false)
  const [paymentSearchQuery, setPaymentSearchQuery] = useState('')

  const [lastOrder, setLastOrder] = useState<any>(null)
  const [showOrderSuccess, setShowOrderSuccess] = useState(false)

  // Tax & service charge settings
  const [taxEnabled, setTaxEnabled] = useState(true)
  const [taxRate, setTaxRate] = useState(11)
  const [scEnabled, setScEnabled] = useState(false)
  const [scRate, setScRate] = useState(5)
  const [dineInRequireTable, setDineInRequireTable] = useState(false)
  const [posOrderFlow, setPosOrderFlow] = useState<'default' | 'cashier_first'>('default')
  const [assignTableOrderId, setAssignTableOrderId] = useState<string | null>(null)
  const [assignTableValue, setAssignTableValue] = useState('')

  // Online payment state
  const [hasOnlinePayment, setHasOnlinePayment] = useState(false)
  const [showOnlinePayment, setShowOnlinePayment] = useState(false)
  const [onlinePaymentData, setOnlinePaymentData] = useState<any>(null)
  const [onlinePaymentLoading, setOnlinePaymentLoading] = useState(false)
  const [showVABankSelect, setShowVABankSelect] = useState(false)

  // Payment detail step state
  const [paymentStep, setPaymentStep] = useState<'select' | 'detail'>('select')
  const [selectedPaymentMethod, setSelectedPaymentMethod] = useState('')
  const [approvalCode, setApprovalCode] = useState('')
  const [cashReceived, setCashReceived] = useState('')
  // Payment detail for existing orders
  const [payingOrderId, setPayingOrderId] = useState<string | null>(null)
  const [payingOrderTotal, setPayingOrderTotal] = useState(0)

  // Promo/discount state
  const [promoCode, setPromoCode] = useState('')
  const [appliedPromo, setAppliedPromo] = useState<any>(null)
  const [promoLoading, setPromoLoading] = useState(false)
  const [promoError, setPromoError] = useState('')

  const printer = useThermalPrinter()
  const [printerSettings, setPrinterSettings] = useState({
    thermal_printer_enabled: 'false',
    thermal_paper_width: '80mm',
    thermal_auto_print_receipt: 'false',
    thermal_auto_print_kitchen: 'false',
    receipt_show_browser_popup: 'true',
    receipt_feedback_qr: 'true',
  })

  const thermalOpts: ThermalPrintOptions | undefined =
    printer.isConnected && printerSettings.thermal_printer_enabled === 'true'
      ? { print: printer.print, paper: printerSettings.thermal_paper_width as '58mm' | '80mm' }
      : undefined

  const receiptTemplate = extractReceiptTemplate(printerSettings)

  const { user: authUser, setUser: setAuthUser } = useAuthStore()

  // Offline mode
  const { isOnline } = useOnlineStatus()
  const [pendingOrderCount, setPendingOrderCount] = useState(0)
  const [missedOrdersCount, setMissedOrdersCount] = useState(0)
  const [showMissedAlert, setShowMissedAlert] = useState(false)
  const prevOnlineRef = useRef(true)
  const notifCountBeforeOfflineRef = useRef(0)

  const updatePendingCount = useCallback(async () => {
    const count = await getOfflineOrderCount()
    setPendingOrderCount(count)
  }, [])

  const { syncOrders } = useOfflineSync({
    isOnline,
    onSyncComplete: (count) => {
      toast.success(`${count} order offline berhasil disinkronkan!`)
      fetchNotifications()
      updatePendingCount()
    },
    onSyncError: (_id, error) => {
      toast.error(`Gagal sync order: ${error}`)
      updatePendingCount()
    },
  })

  const { status: sseStatus, showReconnected } = useSSE({
    storeId: selectedStore,
    onNotificationCreated: (data: any) => {
      fetchNotifications()
      notify(data.title || '🔔 Notifikasi Baru', {
        body: data.message || '',
        tag: `notif-${data.notificationId || Date.now()}`,
      })
    },
    onOrderCreated: (data: any) => {
      fetchNotifications()
      const info = data.tableNumber ? `Meja ${data.tableNumber}` : (data.orderType === 'takeaway' ? 'Takeaway' : '')
      notify('🔔 Pesanan Baru!', {
        body: `Order ${data.orderNumber || ''}${info ? ' - ' + info : ''}`,
        tag: `order-${data.orderId}`,
      })
    },
    onOrderUpdated: () => fetchNotifications(),
    enabled: !!selectedStore,
  })

  useEffect(() => {
    // Load auth user + check store-inactive status
    fetch('/api/auth/me').then(async (r) => {
      if (r.status === 403) {
        const data = await r.json()
        if (data.error === 'STORE_INACTIVE') { router.push('/store-inactive'); return }
      }
      if (r.ok) {
        const data = await r.json()
        if (data.user) setAuthUser(data.user)
      }
    }).catch(() => {})

    async function loadPOSData() {
      try {
        const [catData, menuData, storeData, subData, settingsData] = await Promise.all([
          fetch('/api/categories').then(r => r.json()),
          fetch('/api/menu').then(r => r.json()),
          fetch('/api/stores').then(r => r.json()),
          fetch('/api/tenant/subscription').then(r => r.json()).catch(() => null),
          fetch('/api/settings').then(r => r.json()).catch(() => null),
        ])

        setCategories(catData.categories || [])
        setMenuItems(menuData.menuItems || [])
        setStores(storeData.stores || [])
        if (storeData.stores?.length > 0) setSelectedStore(storeData.stores[0].id)
        if (settingsData?.settings) {
          const s = settingsData.settings
          setTaxEnabled(s.tax_enabled === 'true')
          setTaxRate(parseFloat(s.tax_rate) || 0)
          setScEnabled(s.service_charge_enabled === 'true')
          setScRate(parseFloat(s.service_charge_rate) || 0)
          setDineInRequireTable(s.dine_in_require_table === 'true')
          if (s.pos_order_flow === 'cashier_first') setPosOrderFlow('cashier_first')
        }
        if (subData?.subscription?.plan?.features) {
          const rawFeatures = subData.subscription.plan.features
          const features = Array.isArray(rawFeatures) ? rawFeatures : (() => { try { return JSON.parse(rawFeatures) } catch { return [] } })()
          if (features.includes('online_payment')) setHasOnlinePayment(true)
        }

        // Cache semua data ke IndexedDB untuk offline
        await Promise.all([
          cachePOSData('categories', catData.categories || []),
          cachePOSData('menuItems', menuData.menuItems || []),
          cachePOSData('stores', storeData.stores || []),
          cachePOSData('subscription', subData),
          cachePOSData('settings', settingsData?.settings || {}),
        ]).catch(() => {})
      } catch {
        // API gagal → load dari cache (offline mode)
        const [cats, items, strs, sub, sets] = await Promise.all([
          getCachedPOSData<any[]>('categories'),
          getCachedPOSData<any[]>('menuItems'),
          getCachedPOSData<any[]>('stores'),
          getCachedPOSData<any>('subscription'),
          getCachedPOSData<Record<string, string>>('settings'),
        ])

        if (cats && items && strs) {
          setCategories(cats)
          setMenuItems(items)
          setStores(strs)
          if (strs.length > 0) setSelectedStore(strs[0].id)
          if (sets) {
            setTaxEnabled(sets.tax_enabled === 'true')
            setTaxRate(parseFloat(sets.tax_rate) || 0)
            setScEnabled(sets.service_charge_enabled === 'true')
            setScRate(parseFloat(sets.service_charge_rate) || 0)
            setDineInRequireTable(sets.dine_in_require_table === 'true')
            if (sets.pos_order_flow === 'cashier_first') setPosOrderFlow('cashier_first')
          }
          if (sub?.subscription?.plan?.features) {
            const rawFeatures = sub.subscription.plan.features
            const features = Array.isArray(rawFeatures) ? rawFeatures : (() => { try { return JSON.parse(rawFeatures) } catch { return [] } })()
            if (features.includes('online_payment')) setHasOnlinePayment(true)
          }
          toast('Mode offline — data dari cache', { icon: '📶' })
        } else {
          toast.error('Tidak ada koneksi dan tidak ada data cache')
        }
      }
      setLoading(false)
      updatePendingCount()
    }
    loadPOSData()
  }, []) // eslint-disable-line react-hooks/exhaustive-deps

  useEffect(() => {
    if (selectedStore) {
      fetch(`/api/tables?storeId=${selectedStore}`)
        .then(r => r.json())
        .then(d => {
          setTables(d.tables || [])
          cachePOSData(`tables_${selectedStore}`, d.tables || []).catch(() => {})
        })
        .catch(async () => {
          // Fallback ke cache
          const cached = await getCachedPOSData<any[]>(`tables_${selectedStore}`)
          if (cached) setTables(cached)
        })
    }
  }, [selectedStore])

  // Poll notifications and payment orders (only when online)
  const fetchNotifications = useCallback(async () => {
    if (!selectedStore || !isOnline) return
    try {
      const [notifRes, ordersRes] = await Promise.all([
        fetch(`/api/notifications?storeId=${selectedStore}&unreadOnly=true`).then(r => r.json()),
        fetch(`/api/orders?storeId=${selectedStore}`).then(r => r.json()),
      ])
      const notifs = notifRes.notifications || []
      setNotifications(notifs)

      // Find unpaid orders that want to pay at cashier (all statuses so customer can pay anytime)
      const unpaid = (ordersRes.orders || []).filter(
        (o: any) => o.paymentStatus === 'unpaid' && o.paymentType === 'pay_at_cashier' &&
          !['cancelled'].includes(o.status)
      )
      setPaymentOrders(unpaid)

      // New notification sound
      if (notifs.length > lastNotifCount && lastNotifCount > 0) {
        try {
          const audio = new Audio('data:audio/wav;base64,UklGRnoGAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQoGAACBhYqFbF1fdJivrJBhNjVgiKu0nGRAMFJ+nK2lcUgxPWuMoqyXbEU0SXeRnq6ZYEQ0SHaQm62YX0M0SHWPm62YXkM0R3SOmqyXXkI0R3OOmayXXUI0RnONl6yWXEE0RXKMlquVW0A0RHGLlKqUWj80RHCKk6mTWj80Q2+Jk6iTWT40Q26IkqeSWD00Qm2HkaaRVzw0QWyGkKWQVjw0QGuFj6SPVTs0QGqEjqOOVDs0P2mDjaKNUzo0P2iCjKGMUjk0PmeBi6CLUTk0PmZ/iqCKUDg0PWV+iZ+JTzg0PGRPGBAA')
          audio.volume = 0.3
          audio.play().catch(() => {})
        } catch {}
      }
      setLastNotifCount(notifs.length)
    } catch {}
  }, [selectedStore, lastNotifCount, isOnline])

  useEffect(() => {
    fetchNotifications()
  }, [fetchNotifications])

  // Deteksi transisi offline→online: cek pesanan yang masuk saat offline
  useEffect(() => {
    if (prevOnlineRef.current === false && isOnline) {
      // Baru saja kembali online!
      const checkMissedOrders = async () => {
        if (!selectedStore) return
        try {
          const [notifRes, ordersRes] = await Promise.all([
            fetch(`/api/notifications?storeId=${selectedStore}&unreadOnly=true`).then(r => r.json()),
            fetch(`/api/orders?storeId=${selectedStore}`).then(r => r.json()),
          ])
          const notifs = notifRes.notifications || []
          setNotifications(notifs)

          const unpaid = (ordersRes.orders || []).filter(
            (o: any) => o.paymentStatus === 'unpaid' && o.paymentType === 'pay_at_cashier' &&
              !['cancelled'].includes(o.status)
          )
          setPaymentOrders(unpaid)

          // Hitung notif baru yang masuk selama offline
          const newCount = notifs.length - notifCountBeforeOfflineRef.current
          if (newCount > 0) {
            setMissedOrdersCount(newCount)
            setShowMissedAlert(true)
            // Play alert sound (lebih keras)
            try {
              const audio = new Audio('data:audio/wav;base64,UklGRnoGAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQoGAACBhYqFbF1fdJivrJBhNjVgiKu0nGRAMFJ+nK2lcUgxPWuMoqyXbEU0SXeRnq6ZYEQ0SHaQm62YX0M0SHWPm62YXkM0R3SOmqyXXkI0R3OOmayXXUI0RnONl6yWXEE0RXKMlquVW0A0RHGLlKqUWj80RHCKk6mTWj80Q2+Jk6iTWT40Q26IkqeSWD00Qm2HkaaRVzw0QWyGkKWQVjw0QGuFj6SPVTs0QGqEjqOOVDs0P2mDjaKNUzo0P2iCjKGMUjk0PmeBi6CLUTk0PmZ/iqCKUDg0PWV+iZ+JTzg0PGRPGBAA')
              audio.volume = 0.8
              audio.play().catch(() => {})
            } catch {}
            // Auto-dismiss setelah 15 detik
            setTimeout(() => setShowMissedAlert(false), 15000)
          }
          setLastNotifCount(notifs.length)
        } catch {}
      }
      checkMissedOrders()
    }

    // Track: simpan jumlah notif saat akan offline
    if (prevOnlineRef.current === true && !isOnline) {
      notifCountBeforeOfflineRef.current = notifications.length
    }

    prevOnlineRef.current = isOnline
  }, [isOnline, selectedStore]) // eslint-disable-line react-hooks/exhaustive-deps

  // Customer autocomplete search (only when online)
  useEffect(() => {
    if (customerPhone.length < 2 || !isOnline) {
      setCustomerSuggestions([])
      setShowSuggestions(false)
      return
    }
    const timer = setTimeout(async () => {
      try {
        const res = await fetch(`/api/customers/search?q=${encodeURIComponent(customerPhone)}`)
        if (res.ok) {
          const data = await res.json()
          setCustomerSuggestions(data.customers || [])
          setShowSuggestions((data.customers || []).length > 0)
        }
      } catch {
        // Ignore search errors
      }
    }, 300)
    return () => clearTimeout(timer)
  }, [customerPhone, isOnline])

  const filteredItems = menuItems.filter(item => {
    const matchSearch = item.name.toLowerCase().includes(search.toLowerCase())
    const matchCat = !selectedCategory || item.categoryId === selectedCategory
    return matchSearch && matchCat && item.isAvailable && isMenuAvailableNow(item)
  })

  const addToCart = (item: any) => {
    if (item.variantGroups?.length > 0) {
      // Show variant selection modal
      setVariantSelectItem(item)
      setVariantSelections({})
      setShowVariantSelect(true)
      return
    }

    // No variants - add directly
    const cartKey = item.id
    setCart(prev => {
      const existing = prev.find(c => c.cartKey === cartKey)
      if (existing) return prev.map(c => c.cartKey === cartKey ? { ...c, quantity: c.quantity + 1 } : c)
      return [...prev, { cartKey, menuItemId: item.id, name: item.name, price: Number(item.price), quantity: 1, notes: '', selectedVariants: [] }]
    })
  }

  const handleVariantToggle = (groupId: string, variantId: string, maxSelect: number) => {
    setVariantSelections(prev => {
      const current = prev[groupId] || []
      if (maxSelect === 1) {
        return { ...prev, [groupId]: [variantId] }
      }
      if (current.includes(variantId)) {
        return { ...prev, [groupId]: current.filter(id => id !== variantId) }
      }
      if (current.length >= maxSelect) return prev
      return { ...prev, [groupId]: [...current, variantId] }
    })
  }

  const handleAddWithVariants = () => {
    if (!variantSelectItem) return

    // Validate required groups
    for (const group of variantSelectItem.variantGroups || []) {
      if (group.required) {
        const selected = variantSelections[group.id] || []
        if (selected.length === 0) {
          toast.error(`Pilih minimal 1 opsi untuk "${group.name}"`)
          return
        }
      }
    }

    // Build selected variants array
    const selectedVariants: SelectedVariant[] = []
    for (const group of variantSelectItem.variantGroups || []) {
      const selectedIds = variantSelections[group.id] || []
      for (const vid of selectedIds) {
        const variant = group.variants.find((v: any) => v.id === vid)
        if (variant) {
          selectedVariants.push({
            variantId: variant.id,
            groupName: group.name,
            name: variant.name,
            priceAdjustment: Number(variant.priceAdjustment),
          })
        }
      }
    }

    // Build cart key
    const sortedVariantIds = selectedVariants.map(v => v.variantId).sort()
    const cartKey = sortedVariantIds.length > 0
      ? `${variantSelectItem.id}__${sortedVariantIds.join('-')}`
      : variantSelectItem.id

    setCart(prev => {
      const existing = prev.find(c => c.cartKey === cartKey)
      if (existing) return prev.map(c => c.cartKey === cartKey ? { ...c, quantity: c.quantity + 1 } : c)
      return [...prev, {
        cartKey,
        menuItemId: variantSelectItem.id,
        name: variantSelectItem.name,
        price: Number(variantSelectItem.price),
        quantity: 1,
        notes: '',
        selectedVariants,
      }]
    })

    setShowVariantSelect(false)
    setVariantSelectItem(null)
    setVariantSelections({})
  }

  const updateQuantity = (cartKey: string, delta: number) => {
    setCart(prev => prev.map(c => {
      if (c.cartKey === cartKey) {
        const newQty = c.quantity + delta
        return newQty <= 0 ? null : { ...c, quantity: newQty }
      }
      return c
    }).filter(Boolean) as CartItem[])
  }

  const removeFromCart = (cartKey: string) => {
    setCart(prev => prev.filter(c => c.cartKey !== cartKey))
  }

  const updateItemNotes = (cartKey: string, notes: string) => {
    setCart(prev => prev.map(c => c.cartKey === cartKey ? { ...c, notes } : c))
  }

  const getItemTotalPrice = (item: CartItem) => {
    const variantExtra = item.selectedVariants.reduce((sum, v) => sum + v.priceAdjustment, 0)
    return (item.price + variantExtra) * item.quantity
  }

  const subtotal = cart.reduce((sum, item) => sum + getItemTotalPrice(item), 0)
  const discountAmount = loyaltyDiscount > 0 ? loyaltyDiscount : (appliedPromo?.discountAmount || 0)
  const taxableAmount = subtotal - discountAmount
  const tax = taxEnabled ? Math.round(taxableAmount * taxRate / 100) : 0
  const serviceCharge = scEnabled ? Math.round(taxableAmount * scRate / 100) : 0
  const rawTotal = subtotal - discountAmount + tax + serviceCharge
  // Rounding ke kelipatan 100 jika ada pajak/service charge
  const hasRounding = taxEnabled || scEnabled
  const roundedTotal = hasRounding ? Math.round(rawTotal / 100) * 100 : rawTotal
  const rounding = roundedTotal - rawTotal
  const total = roundedTotal

  const handleApplyPromo = async () => {
    if (!promoCode.trim()) return
    if (!isOnline) { toast.error('Promo tidak tersedia saat offline'); return }
    setPromoLoading(true)
    setPromoError('')
    try {
      const res = await fetch('/api/promotions/validate', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          promoCode: promoCode.trim().toUpperCase(),
          storeId: selectedStore,
          items: cart.map(item => ({
            menuItemId: item.menuItemId,
            quantity: item.quantity,
            unitPrice: item.price + item.selectedVariants.reduce((s: number, v: any) => s + v.priceAdjustment, 0),
            subtotal: getItemTotalPrice(item),
          })),
          subtotal,
        }),
      })
      const data = await res.json()
      if (!res.ok || data.error) {
        setPromoError(data.error || 'Kode promo tidak valid')
        setAppliedPromo(null)
      } else {
        const promo = data.discount || data
        setAppliedPromo(promo)
        setPromoError('')
        toast.success(`Promo "${promo.name}" berhasil diterapkan!`)
      }
    } catch {
      setPromoError('Gagal memvalidasi promo')
    } finally {
      setPromoLoading(false)
    }
  }

  const handleRemovePromo = () => {
    setAppliedPromo(null)
    setPromoCode('')
    setPromoError('')
  }

  const handleSelectPaymentMethod = (method: string) => {
    setSelectedPaymentMethod(method)
    setApprovalCode('')
    setCashReceived('')
    setPaymentStep('detail')
  }

  const handleConfirmPayment = async () => {
    const paymentMethod = selectedPaymentMethod
    // Validasi
    if (paymentMethod === 'cash') {
      const received = parseFloat(cashReceived)
      if (!received || received < total) {
        toast.error('Uang yang diterima kurang dari total')
        return
      }
    } else {
      if (!approvalCode.trim()) {
        toast.error('Masukkan kode approval')
        return
      }
    }

    if (!selectedStore) { toast.error('Pilih cabang terlebih dahulu'); return }
    if (dineInRequireTable && posOrderFlow !== 'cashier_first' && orderType === 'dine_in' && !selectedTable) {
      toast.error('Dine-in wajib memilih meja')
      return
    }
    setSubmitting(true)
    try {
      const res = await fetch('/api/orders', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          storeId: selectedStore,
          tableId: selectedTable || null,
          items: cart.map(c => ({
            menuItemId: c.menuItemId,
            quantity: c.quantity,
            notes: c.notes,
            selectedVariants: c.selectedVariants,
          })),
          customerName: customerName || null,
          customerPhone: customerPhone || null,
          orderType,
          notes: notes || null,
          promoCode: appliedPromo?.code || null,
          loyaltyPointsToRedeem: loyaltyDiscount > 0 ? loyaltyPointsToRedeem : null,
        }),
      })
      const data = await res.json()
      if (!res.ok) throw new Error(data.error)

      // Build payment update
      const paymentUpdate: Record<string, any> = {
        paymentStatus: 'paid',
        paymentMethod,
        status: 'confirmed',
      }
      if (paymentMethod === 'cash') {
        paymentUpdate.cashReceived = parseFloat(cashReceived)
        paymentUpdate.cashChange = parseFloat(cashReceived) - Number(data.order.total)
      } else {
        paymentUpdate.approvalCode = approvalCode.trim()
      }

      await fetch(`/api/orders/${data.order.id}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(paymentUpdate),
      })

      // Fetch full order for receipt
      const fullOrderRes = await fetch(`/api/orders/${data.order.id}`)
      const fullOrderData = await fullOrderRes.json()
      const completedOrder = { ...fullOrderData.order, paymentMethod }
      setLastOrder(completedOrder)
      setShowOrderSuccess(true)
      toast.success(`Order ${data.order.orderNumber} berhasil!`)
      setCart([]); setCustomerName(''); setCustomerPhone(''); setSelectedTable(''); setNotes(''); setShowCheckout(false)
      setShowSuggestions(false)
      setAppliedPromo(null); setPromoCode(''); setPromoError('')
      setSelectedCustomerId(null)
      setLoyaltyInfo(null)
      setLoyaltyPointsToRedeem(0)
      setLoyaltyDiscount(0)
      setPaymentStep('select')
      setSelectedPaymentMethod('')
      setApprovalCode('')
      setCashReceived('')

      // Auto-print if enabled
      const store = stores.find((s: any) => s.id === selectedStore)
      const restaurantName = authUser?.tenant?.name || store?.name || '-'
      const storeName = store?.name || ''
      const feedbackUrl = printerSettings.receipt_feedback_qr === 'true' && completedOrder.feedbackToken ? `${window.location.origin}/f/${completedOrder.feedbackToken}` : null
      const receiptData = orderToReceiptData(completedOrder, restaurantName, storeName, { feedbackUrl, taxRate, serviceChargeRate: scRate })
      const showPopup = printerSettings.receipt_show_browser_popup !== 'false'

      if (printerSettings.thermal_auto_print_receipt === 'true') {
        // Small delay to ensure success modal is rendered first
        await new Promise(r => setTimeout(r, 500))
        try {
          const result = await printReceipt(receiptData, 'customer', thermalOpts, receiptTemplate, showPopup)
          if (result.success) {
            toast.success(result.method === 'thermal' ? 'Nota otomatis terkirim ke printer' : 'Auto cetak nota...')
          } else {
            toast.error(result.error || 'Auto cetak nota gagal')
          }
        } catch (e) { console.error('[POS] Auto print receipt error:', e) }
      }
      if (printerSettings.thermal_auto_print_kitchen === 'true') {
        try {
          const result = await printReceipt(receiptData, 'kitchen', thermalOpts, receiptTemplate, showPopup)
          if (result.success) {
            toast.success(result.method === 'thermal' ? 'Tiket dapur otomatis terkirim ke printer' : 'Auto cetak tiket dapur...')
          } else {
            toast.error(result.error || 'Auto cetak tiket dapur gagal')
          }
        } catch (e) { console.error('[POS] Auto print kitchen error:', e) }
      }
    } catch (err: any) {
      // Cek apakah network error (TypeError dari fetch = server/internet unreachable)
      // vs server error (Error dari throw = server merespons tapi gagal)
      const isNetworkError = err instanceof TypeError || !navigator.onLine || !isOnline

      if (isNetworkError) {
        // Network error → simpan order ke IndexedDB queue (offline fallback)
        try {
          const offlineOrder = await addOfflineOrder({
            storeId: selectedStore,
            tableId: selectedTable || null,
            items: cart.map(c => ({
              menuItemId: c.menuItemId,
              quantity: c.quantity,
              notes: c.notes,
              selectedVariants: c.selectedVariants,
            })),
            customerName: customerName || null,
            customerPhone: customerPhone || null,
            orderType,
            notes: notes || null,
            paymentMethod: selectedPaymentMethod,
            approvalCode: approvalCode || undefined,
            cashReceived: cashReceived ? parseFloat(cashReceived) : undefined,
          })
          setLastOrder({
            orderNumber: offlineOrder.tempOrderNumber,
            total,
            offline: true,
          })
          setShowOrderSuccess(true)
          toast(`Order ${offlineOrder.tempOrderNumber} disimpan offline`, { icon: '📶' })
          setCart([]); setCustomerName(''); setCustomerPhone(''); setSelectedTable(''); setNotes(''); setShowCheckout(false)
          setShowSuggestions(false)
          setAppliedPromo(null); setPromoCode(''); setPromoError('')
          setSelectedCustomerId(null)
          setLoyaltyInfo(null)
          setLoyaltyPointsToRedeem(0)
          setLoyaltyDiscount(0)
          setPaymentStep('select')
          setSelectedPaymentMethod('')
          setApprovalCode('')
          setCashReceived('')
          updatePendingCount()
        } catch {
          toast.error('Gagal menyimpan order offline')
        }
      } else {
        // Server error (validasi gagal, dll) → tampilkan pesan error
        toast.error(err.message || 'Gagal membuat order')
      }
    } finally { setSubmitting(false) }
  }

  const handleSelectPaymentForExisting = (orderId: string, orderTotal: number, method: string) => {
    setPayingOrderId(orderId)
    setPayingOrderTotal(orderTotal)
    setSelectedPaymentMethod(method)
    setApprovalCode('')
    setCashReceived('')
    setPaymentStep('detail')
  }

  const handleConfirmExistingPayment = async () => {
    if (!payingOrderId) return
    const paymentMethod = selectedPaymentMethod

    // Validasi
    if (paymentMethod === 'cash') {
      const received = parseFloat(cashReceived)
      if (!received || received < payingOrderTotal) {
        toast.error('Uang yang diterima kurang dari total')
        return
      }
    } else {
      if (!approvalCode.trim()) {
        toast.error('Masukkan kode approval')
        return
      }
    }

    try {
      const paymentUpdate: Record<string, any> = {
        paymentStatus: 'paid',
        paymentMethod,
        status: 'completed',
      }
      if (paymentMethod === 'cash') {
        paymentUpdate.cashReceived = parseFloat(cashReceived)
        paymentUpdate.cashChange = parseFloat(cashReceived) - payingOrderTotal
      } else {
        paymentUpdate.approvalCode = approvalCode.trim()
      }

      await fetch(`/api/orders/${payingOrderId}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(paymentUpdate),
      })
      // Fetch full order for receipt
      const fullOrderRes = await fetch(`/api/orders/${payingOrderId}`)
      const fullOrderData = await fullOrderRes.json()
      setLastOrder({ ...fullOrderData.order, paymentMethod })
      setShowOrderSuccess(true)
      toast.success('Pembayaran berhasil!')
      fetchNotifications()
      setPayingOrderId(null)
      setPayingOrderTotal(0)
      setPaymentStep('select')
      setSelectedPaymentMethod('')
      setApprovalCode('')
      setCashReceived('')
    } catch {
      toast.error('Gagal memproses pembayaran')
    }
  }

  const handleOnlinePayment = async (method: 'qris' | 'va', channel: string) => {
    if (!selectedStore) { toast.error('Pilih cabang terlebih dahulu'); return }
    setOnlinePaymentLoading(true)
    setShowVABankSelect(false)
    try {
      // Create order first
      const orderRes = await fetch('/api/orders', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          storeId: selectedStore,
          tableId: selectedTable || null,
          items: cart.map(c => ({
            menuItemId: c.menuItemId,
            quantity: c.quantity,
            notes: c.notes,
            selectedVariants: c.selectedVariants,
          })),
          customerName: customerName || null,
          customerPhone: customerPhone || null,
          orderType,
          notes: notes || null,
          promoCode: appliedPromo?.code || null,
          loyaltyPointsToRedeem: loyaltyDiscount > 0 ? loyaltyPointsToRedeem : null,
        }),
      })
      const orderData = await orderRes.json()
      if (!orderRes.ok) throw new Error(orderData.error)

      // Create payment
      const payRes = await fetch('/api/payment/create', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          orderId: orderData.order.id,
          paymentMethod: method,
          paymentChannel: channel,
        }),
      })
      const payData = await payRes.json()
      if (!payRes.ok) throw new Error(payData.error)

      setOnlinePaymentData({
        ...payData,
        orderId: orderData.order.id,
        orderNumber: orderData.order.orderNumber,
      })
      setShowCheckout(false)
      setShowOnlinePayment(true)
      setCart([]); setCustomerName(''); setCustomerPhone(''); setSelectedTable(''); setNotes('')
      setShowSuggestions(false)
      setAppliedPromo(null); setPromoCode(''); setPromoError('')
      setSelectedCustomerId(null)
      setLoyaltyInfo(null)
      setLoyaltyPointsToRedeem(0)
      setLoyaltyDiscount(0)
    } catch (err: any) {
      toast.error(err.message || 'Gagal membuat pembayaran online')
    } finally { setOnlinePaymentLoading(false) }
  }

  // Poll online payment status
  useEffect(() => {
    if (!showOnlinePayment || !onlinePaymentData?.referenceId) return
    const interval = setInterval(async () => {
      try {
        const res = await fetch(`/api/public/payment/status/${onlinePaymentData.referenceId}`)
        const data = await res.json()
        if (data.status === 'paid') {
          setOnlinePaymentData(null)
          setShowOnlinePayment(false)
          toast.success(`Pembayaran ${onlinePaymentData.orderNumber} berhasil!`)
          fetchNotifications()
        } else if (data.status === 'expired' || data.status === 'failed') {
          toast.error('Pembayaran expired/gagal')
          setOnlinePaymentData(null)
          setShowOnlinePayment(false)
        }
      } catch {}
    }, 3000)
    return () => clearInterval(interval)
  }, [showOnlinePayment, onlinePaymentData?.referenceId]) // eslint-disable-line react-hooks/exhaustive-deps

  useEffect(() => {
    fetch('/api/settings/printer')
      .then(r => r.json())
      .then(d => {
        if (d.settings) {
          setPrinterSettings(d.settings)
          cachePOSData('printerSettings', d.settings).catch(() => {})
        }
      })
      .catch(async () => {
        const cached = await getCachedPOSData<typeof printerSettings>('printerSettings')
        if (cached) setPrinterSettings(cached)
      })
  }, [])

  const handleDismissNotif = async (id: string) => {
    await fetch(`/api/notifications/${id}`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ isRead: true }),
    })
    fetchNotifications()
  }

  const unreadCount = notifications.filter(n => !n.isRead).length

  if (featureLoading || loading) {
    return (
      <div className="min-h-screen flex items-center justify-center bg-gray-100 dark:bg-gray-700/50">
        <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-primary-600"></div>
      </div>
    )
  }

  if (!featureAllowed) {
    return <FeatureBlockedPage featureLabel="Point of Sale (POS)" />
  }

  return (
    <div className="h-screen flex flex-col bg-gray-100 dark:bg-gray-700/50">
      {/* Top Bar */}
      <header className="bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 px-4 py-3 flex items-center justify-between flex-shrink-0">
        <div className="flex items-center gap-3">
          <button onClick={() => router.push('/dashboard')} className="btn-ghost p-2"><ArrowLeft className="w-5 h-5" /></button>
          <UtensilsCrossed className="w-6 h-6 text-primary-600" />
          <h1 className="text-lg font-bold text-gray-900 dark:text-white">POS System</h1>
        </div>
        <div className="flex items-center gap-3">
          <select className="input-field text-sm w-auto dark:bg-gray-800 dark:border-gray-600 dark:text-white" value={selectedStore} onChange={(e) => setSelectedStore(e.target.value)}>
            {stores.map(s => <option key={s.id} value={s.id}>{s.name}</option>)}
          </select>

          {/* Thermal Printer Button */}
          {printer.isSupported && printerSettings.thermal_printer_enabled === 'true' && (
            <div className="flex items-center gap-1 relative">
              {printer.isConnected ? (
                <>
                  <button
                    onClick={() => printer.disconnect()}
                    className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm font-medium transition-colors bg-green-100 text-green-700 hover:bg-green-200 dark:bg-green-900/30 dark:text-green-400 dark:hover:bg-green-900/50"
                    title={`Terhubung: ${printer.deviceName} (${printer.connectionType === 'serial' ? 'Serial' : 'USB'})`}
                  >
                    <Printer className="w-4 h-4" />
                    {printer.deviceName?.slice(0, 15) || 'Printer'}
                  </button>
                  <button
                    onClick={async () => {
                      toast.loading('Mengirim test print...', { id: 'test-print' })
                      const bytes = buildTestReceipt(authUser?.tenant?.name || '-', printerSettings.thermal_paper_width as '58mm' | '80mm')
                      const ok = await printer.print(bytes)
                      if (ok) {
                        toast.success('Test print berhasil! Cek printer.', { id: 'test-print' })
                      } else {
                        toast.error(`Gagal: ${printer.error || 'Periksa koneksi printer'}`, { id: 'test-print' })
                      }
                    }}
                    disabled={printer.isPrinting}
                    className="px-2 py-1.5 rounded-lg text-xs font-medium bg-blue-100 text-blue-700 hover:bg-blue-200 dark:bg-blue-900/30 dark:text-blue-400 dark:hover:bg-blue-900/50 transition-colors disabled:opacity-50"
                    title="Test Print"
                  >
                    {printer.isPrinting ? '...' : 'Test'}
                  </button>
                </>
              ) : printer.isConnecting ? (
                <button disabled className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm font-medium bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-300">
                  <Loader2 className="w-4 h-4 animate-spin" />
                  Menghubungkan...
                </button>
              ) : (
                <div className="flex items-center gap-1">
                  <button
                    onClick={async () => {
                      const ok = await printer.connectSerial()
                      if (ok) toast.success('Printer terhubung via Serial!')
                      else if (printer.error) toast.error(printer.error)
                    }}
                    className={`flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm font-medium transition-colors ${
                      printer.error
                        ? 'bg-red-100 text-red-700 hover:bg-red-200 dark:bg-red-900/30 dark:text-red-400 dark:hover:bg-red-900/50'
                        : 'bg-gray-100 text-gray-600 hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600'
                    }`}
                    title={printer.error || 'Hubungkan Printer (Serial/COM Port - Recommended)'}
                  >
                    <Printer className="w-4 h-4" />
                    {printer.error ? 'Error' : 'Printer'}
                  </button>
                  {printer.isUSBSupported && (
                    <button
                      onClick={async () => {
                        const ok = await printer.connectUSB()
                        if (ok) toast.success('Printer terhubung via USB!')
                        else if (printer.error) toast.error(printer.error)
                      }}
                      className="px-2 py-1.5 rounded-lg text-xs font-medium bg-gray-100 text-gray-500 hover:bg-gray-200 dark:bg-gray-700 dark:text-gray-400 dark:hover:bg-gray-600 transition-colors"
                      title="Hubungkan via USB (memerlukan driver WinUSB)"
                    >
                      USB
                    </button>
                  )}
                </div>
              )}
            </div>
          )}

          {/* Payment Orders Button (online only) */}
          {isOnline && (
          <button onClick={() => setShowPaymentOrders(true)} className="relative p-2 rounded-lg bg-yellow-50 dark:bg-yellow-900/30 text-yellow-700 dark:text-yellow-300 hover:bg-yellow-100 dark:hover:bg-yellow-900/50 border border-yellow-200 dark:border-yellow-800">
            <HandCoins className="w-5 h-5" />
            {paymentOrders.length > 0 && (
              <span className="absolute -top-1 -right-1 w-5 h-5 bg-yellow-500 text-white rounded-full text-xs flex items-center justify-center font-bold animate-pulse">
                {paymentOrders.length}
              </span>
            )}
          </button>
          )}

          {/* Browser Notification Permission */}
          {isOnline && notifPermission !== 'granted' && (
            <button
              onClick={requestPermission}
              className={`p-2 rounded-lg ${notifPermission === 'denied' ? 'bg-red-100 dark:bg-red-900/30 text-red-400 cursor-not-allowed' : 'bg-yellow-100 dark:bg-yellow-900/30 text-yellow-600 animate-pulse'}`}
              title={notifPermission === 'denied' ? 'Notifikasi browser diblokir' : 'Aktifkan notifikasi browser'}
            >
              <BellRing className="w-5 h-5" />
            </button>
          )}

          {/* Notifications Button (online only) */}
          {isOnline && (
          <button onClick={() => setShowNotifications(true)} className="relative p-2 rounded-lg bg-gray-100 dark:bg-gray-700/50 text-gray-600 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600">
            {unreadCount > 0 ? <BellRing className="w-5 h-5 text-red-500" /> : <Bell className="w-5 h-5" />}
            {unreadCount > 0 && (
              <span className="absolute -top-1 -right-1 w-5 h-5 bg-red-500 text-white rounded-full text-xs flex items-center justify-center font-bold animate-pulse">
                {unreadCount}
              </span>
            )}
          </button>
          )}
        </div>
      </header>

      {/* Offline mode banner */}
      {!isOnline && (
        <div className="bg-orange-500 text-white px-4 py-2 text-center text-sm font-medium flex items-center justify-center gap-2 flex-shrink-0">
          <WifiOff className="w-4 h-4" />
          <span>Mode Offline — Order disimpan lokal, akan sync otomatis saat online</span>
        </div>
      )}

      {/* Pending sync indicator */}
      {pendingOrderCount > 0 && isOnline && (
        <div className="bg-blue-500 text-white px-4 py-2 text-center text-sm font-medium flex items-center justify-center gap-2 flex-shrink-0">
          <Loader2 className="w-4 h-4 animate-spin" />
          <span>Menyinkronkan {pendingOrderCount} order offline...</span>
        </div>
      )}

      {isOnline && sseStatus === 'disconnected' && (
        <div className="bg-red-600 text-white px-4 py-2 flex items-center justify-center gap-2 text-sm animate-pulse flex-shrink-0">
          <WifiOff className="w-4 h-4" />
          <span>Koneksi terputus. Mencoba menghubungkan kembali...</span>
        </div>
      )}
      {showReconnected && (
        <div className="bg-green-600 text-white px-4 py-2 flex items-center justify-center gap-2 text-sm flex-shrink-0">
          <CheckCircle2 className="w-4 h-4" />
          <span>Terhubung kembali</span>
        </div>
      )}

      {/* Alert: pesanan masuk saat offline */}
      {showMissedAlert && missedOrdersCount > 0 && (
        <div className="bg-red-600 text-white px-4 py-3 flex items-center justify-center gap-3 flex-shrink-0 animate-pulse">
          <BellRing className="w-5 h-5 flex-shrink-0" />
          <span className="font-bold text-base">
            ⚠️ {missedOrdersCount} pesanan masuk saat Anda offline! Cek notifikasi & pembayaran kasir.
          </span>
          <button onClick={() => { setShowMissedAlert(false); setShowNotifications(true) }}
            className="bg-white text-red-600 px-3 py-1 rounded-lg text-sm font-bold flex-shrink-0 hover:bg-red-50">
            Lihat
          </button>
          <button onClick={() => setShowMissedAlert(false)}
            className="text-white/70 hover:text-white flex-shrink-0">
            <X className="w-4 h-4" />
          </button>
        </div>
      )}

      <div className="flex flex-1 overflow-hidden">
        {/* Left: Menu */}
        <div className="flex-1 flex flex-col overflow-hidden">
          <div className="p-4 space-y-3 flex-shrink-0">
            <div className="relative">
              <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400 dark:text-gray-500" />
              <input type="text" placeholder="Cari menu..." className="input-field pl-10 dark:bg-gray-800 dark:border-gray-600 dark:text-white" value={search} onChange={(e) => setSearch(e.target.value)} />
            </div>
            <div className="flex gap-2 overflow-x-auto pb-1">
              <button onClick={() => setSelectedCategory('')} className={`px-3 py-1.5 rounded-full text-sm font-medium whitespace-nowrap transition-colors ${!selectedCategory ? 'bg-primary-600 text-white' : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700'}`}>Semua</button>
              {categories.map(cat => (
                <button key={cat.id} onClick={() => setSelectedCategory(cat.id)} className={`px-3 py-1.5 rounded-full text-sm font-medium whitespace-nowrap transition-colors ${selectedCategory === cat.id ? 'bg-primary-600 text-white' : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700'}`}>{cat.name}</button>
              ))}
            </div>
          </div>
          <div className="flex-1 overflow-y-auto p-4 pt-0">
            <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-3">
              {filteredItems.map(item => (
                <button key={item.id} onClick={() => addToCart(item)} className="bg-white dark:bg-gray-800 rounded-xl p-3 text-left hover:shadow-md transition-shadow border border-gray-100 dark:border-gray-700 hover:border-primary-200 dark:hover:border-primary-700">
                  {item.image && <div className="w-full aspect-square bg-gray-100 dark:bg-gray-700/50 rounded-lg mb-2 overflow-hidden"><img src={item.image} alt={item.name} className="w-full h-full object-cover" loading="lazy" /></div>}
                  <h3 className="font-medium text-gray-900 dark:text-white text-sm line-clamp-2">{item.name}</h3>
                  <p className="text-primary-600 font-bold text-sm mt-1">{formatCurrency(item.price)}</p>
                  {item.variantGroups?.length > 0 && (
                    <p className="text-xs text-purple-600 dark:text-purple-400 mt-0.5">{item.variantGroups.length} varian</p>
                  )}
                </button>
              ))}
            </div>
            {filteredItems.length === 0 && <p className="text-center text-gray-500 dark:text-gray-400 py-12">Tidak ada menu ditemukan</p>}
          </div>
        </div>

        {/* Right: Cart */}
        <div className="w-80 lg:w-96 bg-white dark:bg-gray-800 border-l border-gray-200 dark:border-gray-700 flex flex-col">
          <div className="p-4 border-b border-gray-200 dark:border-gray-700 flex-shrink-0">
            <div className="flex items-center justify-between">
              <h2 className="font-semibold text-gray-900 dark:text-white flex items-center gap-2"><ShoppingCart className="w-5 h-5" /> Keranjang</h2>
              <span className="badge bg-primary-100 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300">{cart.length} item</span>
            </div>
          </div>
          <div className="flex-1 overflow-y-auto p-4 space-y-3">
            {cart.length === 0 ? (
              <div className="text-center text-gray-400 dark:text-gray-500 py-12">
                <ShoppingCart className="w-12 h-12 mx-auto mb-2 opacity-50" />
                <p>Keranjang kosong</p>
                <p className="text-sm">Klik menu untuk menambahkan</p>
              </div>
            ) : (
              cart.map(item => (
                <div key={item.cartKey} className="bg-gray-50 dark:bg-gray-900 rounded-lg p-3">
                  <div className="flex items-start justify-between mb-2">
                    <div className="flex-1">
                      <h4 className="font-medium text-gray-900 dark:text-white text-sm">{item.name}</h4>
                      {item.selectedVariants.length > 0 && (
                        <p className="text-xs text-gray-500 dark:text-gray-400">{item.selectedVariants.map(v => v.name).join(', ')}</p>
                      )}
                      <p className="text-primary-600 font-medium text-sm">{formatCurrency(item.price + item.selectedVariants.reduce((s, v) => s + v.priceAdjustment, 0))}</p>
                    </div>
                    <button onClick={() => removeFromCart(item.cartKey)} className="text-gray-400 dark:text-gray-500 hover:text-red-500"><Trash2 className="w-4 h-4" /></button>
                  </div>
                  <div className="flex items-center justify-between">
                    <div className="flex items-center gap-2">
                      <button onClick={() => updateQuantity(item.cartKey, -1)} className="w-7 h-7 rounded-full bg-gray-200 dark:bg-gray-700 flex items-center justify-center hover:bg-gray-300 dark:hover:bg-gray-600"><Minus className="w-3.5 h-3.5" /></button>
                      <span className="font-medium text-sm w-6 text-center">{item.quantity}</span>
                      <button onClick={() => updateQuantity(item.cartKey, 1)} className="w-7 h-7 rounded-full bg-primary-100 dark:bg-primary-900/30 text-primary-600 flex items-center justify-center hover:bg-primary-200 dark:hover:bg-primary-900/50"><Plus className="w-3.5 h-3.5" /></button>
                    </div>
                    <span className="font-bold text-sm">{formatCurrency(getItemTotalPrice(item))}</span>
                  </div>
                  <input type="text" placeholder="Catatan: tidak pedas, dll." className="mt-2 w-full text-xs border border-gray-200 dark:border-gray-600 rounded-lg px-2 py-1.5 focus:outline-none focus:ring-1 focus:ring-primary-500 dark:bg-gray-800 dark:text-white"
                    value={item.notes} onChange={(e) => updateItemNotes(item.cartKey, e.target.value)} />
                </div>
              ))
            )}
          </div>
          {cart.length > 0 && (
            <div className="border-t border-gray-200 dark:border-gray-700 space-y-0 flex-shrink-0">
              {/* Promo Code Section */}
              {loyaltyDiscount === 0 && (
              <div className="px-4 py-2 border-t border-gray-200 dark:border-gray-700">
                {appliedPromo ? (
                  <div className="flex items-center justify-between bg-green-50 dark:bg-green-900/20 rounded-lg p-2">
                    <div className="flex items-center gap-2">
                      <Tag className="w-4 h-4 text-green-600 dark:text-green-400" />
                      <div>
                        <p className="text-sm font-medium text-green-700 dark:text-green-300">{appliedPromo.name}</p>
                        <p className="text-xs text-green-600 dark:text-green-400">{appliedPromo.discountLabel}</p>
                      </div>
                    </div>
                    <button onClick={handleRemovePromo} className="text-red-500 hover:text-red-700 dark:text-red-400">
                      <X className="w-4 h-4" />
                    </button>
                  </div>
                ) : (
                  <div className="flex gap-2">
                    <input
                      type="text"
                      placeholder="Kode Promo"
                      value={promoCode}
                      onChange={(e) => setPromoCode(e.target.value.toUpperCase())}
                      onKeyDown={(e) => e.key === 'Enter' && handleApplyPromo()}
                      className="input-field text-sm flex-1"
                    />
                    <button
                      onClick={handleApplyPromo}
                      disabled={promoLoading || !promoCode.trim()}
                      className="btn-primary text-sm px-3 py-1.5"
                    >
                      {promoLoading ? '...' : 'Terapkan'}
                    </button>
                  </div>
                )}
                {promoError && (
                  <p className="text-xs text-red-500 mt-1">{promoError}</p>
                )}
              </div>
              )}

              {/* Loyalty Points Section */}
              {loyaltyInfo && loyaltyInfo.loyaltyPoints > 0 && !appliedPromo && (
                <div className="px-4 py-2">
                  {loyaltyDiscount > 0 ? (
                    <div className="flex items-center justify-between bg-purple-50 dark:bg-purple-900/20 rounded-lg px-3 py-2">
                      <div>
                        <p className="text-sm font-medium text-purple-700 dark:text-purple-300">
                          🎁 {loyaltyPointsToRedeem} poin digunakan
                        </p>
                        <p className="text-xs text-purple-600 dark:text-purple-400">
                          Diskon {formatCurrency(loyaltyDiscount)}
                        </p>
                      </div>
                      <button
                        type="button"
                        onClick={() => { setLoyaltyPointsToRedeem(0); setLoyaltyDiscount(0) }}
                        className="text-red-500 hover:text-red-700 text-sm"
                      >
                        Hapus
                      </button>
                    </div>
                  ) : (
                    <button
                      type="button"
                      onClick={() => setShowLoyaltyModal(true)}
                      className="w-full flex items-center justify-between px-3 py-2 rounded-lg border border-purple-300 dark:border-purple-700 hover:bg-purple-50 dark:hover:bg-purple-900/20 transition-colors"
                    >
                      <span className="text-sm font-medium text-purple-700 dark:text-purple-300">
                        🏆 Gunakan Poin ({loyaltyInfo.loyaltyPoints} poin • {loyaltyInfo.tier})
                      </span>
                      <span className="text-purple-500">→</span>
                    </button>
                  )}
                </div>
              )}

              {/* Hide promo when loyalty is applied */}
              <div className="p-4 space-y-3">
                <div className="space-y-1 text-sm">
                  <div className="flex justify-between text-gray-600 dark:text-gray-300"><span>Subtotal</span><span>{formatCurrency(subtotal)}</span></div>
                  {discountAmount > 0 && (
                    <div className="flex justify-between text-green-600 dark:text-green-400">
                      <span>{loyaltyDiscount > 0 ? 'Diskon Loyalti' : 'Diskon'}</span>
                      <span>-{formatCurrency(discountAmount)}</span>
                    </div>
                  )}
                  {taxEnabled && <div className="flex justify-between text-gray-600 dark:text-gray-300"><span>Pajak ({taxRate}%)</span><span>{formatCurrency(tax)}</span></div>}
                  {scEnabled && <div className="flex justify-between text-gray-600 dark:text-gray-300"><span>B. Layanan ({scRate}%)</span><span>{formatCurrency(serviceCharge)}</span></div>}
                  <div className="flex justify-between font-bold text-lg text-gray-900 dark:text-white"><span>Total</span><span>{formatCurrency(total)}</span></div>
                </div>
                <button onClick={() => setShowCheckout(true)} className="btn-primary w-full text-center flex items-center justify-center gap-2">
                  <Receipt className="w-5 h-5" /> Proses Pembayaran
                </button>
              </div>
            </div>
          )}
        </div>
      </div>

      {/* Variant Selection Modal */}
      {showVariantSelect && variantSelectItem && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4">
          <div className="bg-white dark:bg-gray-800 rounded-xl w-full max-w-md p-6 max-h-[80vh] overflow-y-auto">
            <div className="flex items-center justify-between mb-4">
              <div>
                <h3 className="text-lg font-semibold dark:text-white">{variantSelectItem.name}</h3>
                <p className="text-sm text-primary-600 font-medium">{formatCurrency(variantSelectItem.price)}</p>
              </div>
              <button onClick={() => { setShowVariantSelect(false); setVariantSelectItem(null) }}><X className="w-5 h-5 text-gray-400 dark:text-gray-500" /></button>
            </div>

            <div className="space-y-4 mb-4">
              {variantSelectItem.variantGroups?.map((group: any) => (
                <div key={group.id}>
                  <div className="flex items-center gap-2 mb-2">
                    <h4 className="font-medium text-gray-900 dark:text-white text-sm">{group.name}</h4>
                    {group.required && <span className="text-xs bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300 px-1.5 py-0.5 rounded font-medium">Wajib</span>}
                    {group.maxSelect > 1 && <span className="text-xs text-gray-500 dark:text-gray-400">(maks {group.maxSelect})</span>}
                  </div>
                  <div className="space-y-1">
                    {group.variants?.map((variant: any) => {
                      const isSelected = (variantSelections[group.id] || []).includes(variant.id)
                      return (
                        <button key={variant.id}
                          onClick={() => handleVariantToggle(group.id, variant.id, group.maxSelect)}
                          className={`w-full flex items-center justify-between px-3 py-2.5 rounded-lg border transition-colors ${
                            isSelected ? 'border-primary-500 bg-primary-50 dark:bg-primary-900/30' : 'border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700'
                          }`}>
                          <div className="flex items-center gap-3">
                            <div className={`w-5 h-5 rounded-${group.maxSelect === 1 ? 'full' : 'md'} border-2 flex items-center justify-center ${
                              isSelected ? 'border-primary-600 bg-primary-600' : 'border-gray-300 dark:border-gray-600'
                            }`}>
                              {isSelected && <div className={`w-2.5 h-2.5 ${group.maxSelect === 1 ? 'rounded-full bg-white' : 'text-white text-xs font-bold'}`}>
                                {group.maxSelect > 1 && <svg className="w-2.5 h-2.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={3} d="M5 13l4 4L19 7" /></svg>}
                              </div>}
                            </div>
                            <span className="text-sm text-gray-900 dark:text-white">{variant.name}</span>
                          </div>
                          {Number(variant.priceAdjustment) > 0 && (
                            <span className="text-sm text-gray-600 dark:text-gray-300">+{formatCurrency(variant.priceAdjustment)}</span>
                          )}
                        </button>
                      )
                    })}
                  </div>
                </div>
              ))}
            </div>

            <button onClick={handleAddWithVariants}
              className="btn-primary w-full py-3 flex items-center justify-center gap-2">
              <Plus className="w-5 h-5" /> Tambah ke Keranjang
            </button>
          </div>
        </div>
      )}

      {/* Checkout Modal */}
      {showCheckout && (
        <div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center bg-black/50">
          <div className="bg-white dark:bg-gray-800 rounded-t-2xl sm:rounded-xl w-full sm:max-w-md max-h-[92vh] sm:max-h-[85vh] flex flex-col sm:m-4">

            {/* ── Sticky Header: Total + Close ── */}
            <div className="flex-shrink-0 px-4 pt-4 pb-3 border-b border-gray-100 dark:border-gray-700">
              <div className="flex items-center justify-between mb-2">
                <h3 className="text-base font-semibold dark:text-white">Pembayaran</h3>
                <button onClick={() => { setShowCheckout(false); setPaymentStep('select'); setSelectedPaymentMethod(''); }}
                  className="p-1 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700"><X className="w-5 h-5 text-gray-400 dark:text-gray-500" /></button>
              </div>
              {/* Compact total summary — always visible */}
              <div className="bg-gray-50 dark:bg-gray-900 rounded-lg px-3 py-2 text-sm space-y-0.5">
                <div className="flex justify-between dark:text-gray-300"><span>Subtotal</span><span>{formatCurrency(subtotal)}</span></div>
                {discountAmount > 0 && (
                  <div className="flex justify-between text-green-600 dark:text-green-400">
                    <span>{loyaltyDiscount > 0 ? 'Diskon Loyalti' : 'Diskon'}</span>
                    <span>-{formatCurrency(discountAmount)}</span>
                  </div>
                )}
                {taxEnabled && <div className="flex justify-between text-xs dark:text-gray-400"><span>Pajak ({taxRate}%)</span><span>{formatCurrency(tax)}</span></div>}
                {scEnabled && <div className="flex justify-between text-xs dark:text-gray-400"><span>B. Layanan ({scRate}%)</span><span>{formatCurrency(serviceCharge)}</span></div>}
                {rounding !== 0 && <div className="flex justify-between text-xs text-gray-400"><span>Pembulatan</span><span>{rounding > 0 ? '+' : ''}{formatCurrency(rounding)}</span></div>}
                <div className="flex justify-between font-bold text-lg dark:text-white pt-0.5 border-t border-gray-200 dark:border-gray-700"><span>Total</span><span className="text-primary-600">{formatCurrency(total)}</span></div>
              </div>
            </div>

            {/* ── Scrollable Middle ── */}
            <div className="flex-1 overflow-y-auto px-4 py-3 space-y-3">

              {paymentStep === 'select' ? (
              <>
                {/* Order Type — compact inline */}
                <div className="grid grid-cols-2 gap-2">
                  <button type="button" onClick={() => { setOrderType('dine_in'); }}
                    className={`flex items-center justify-center gap-1.5 py-2 rounded-lg text-sm font-medium border-2 transition-colors ${
                      orderType === 'dine_in'
                        ? 'border-primary-500 bg-primary-50 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300'
                        : 'border-gray-200 dark:border-gray-600 text-gray-500 dark:text-gray-400'
                    }`}>
                    <UtensilsCrossed className="w-4 h-4" /> Dine In
                  </button>
                  <button type="button" onClick={() => { setOrderType('takeaway'); setSelectedTable(''); }}
                    className={`flex items-center justify-center gap-1.5 py-2 rounded-lg text-sm font-medium border-2 transition-colors ${
                      orderType === 'takeaway'
                        ? 'border-purple-500 bg-purple-50 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300'
                        : 'border-gray-200 dark:border-gray-600 text-gray-500 dark:text-gray-400'
                    }`}>
                    <ShoppingBag className="w-4 h-4" /> Takeaway
                  </button>
                </div>

                {/* Table selector — hidden in cashier_first mode */}
                {orderType === 'dine_in' && tables.length > 0 && posOrderFlow !== 'cashier_first' && (
                  <select className="input-field text-sm dark:bg-gray-800 dark:border-gray-600 dark:text-white" value={selectedTable} onChange={(e) => setSelectedTable(e.target.value)}>
                    <option value="">Tanpa Meja</option>
                    {tables.map(t => <option key={t.id} value={t.id}>{t.name || `Meja ${t.number}`}</option>)}
                  </select>
                )}
                {orderType === 'dine_in' && posOrderFlow === 'cashier_first' && (
                  <p className="text-xs text-gray-500 dark:text-gray-400 bg-gray-50 dark:bg-gray-700/50 rounded-lg px-3 py-2">
                    💡 Meja akan di-assign setelah order dibuat
                  </p>
                )}

                {/* Customer: Phone + Name side-by-side */}
                <div className="grid grid-cols-2 gap-2">
                  <div className="relative">
                    <input type="tel" placeholder="No. HP" value={customerPhone}
                      onChange={(e) => { setCustomerPhone(e.target.value); setShowSuggestions(false); setSelectedCustomerId(null); setLoyaltyInfo(null); setLoyaltyDiscount(0); setLoyaltyPointsToRedeem(0) }}
                      className="input-field text-sm" />
                    {showSuggestions && (
                      <div className="absolute z-50 w-[calc(200%+0.5rem)] mt-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-lg shadow-lg max-h-32 overflow-y-auto">
                        {customerSuggestions.map((c: any) => (
                          <button key={c.id} type="button"
                            onClick={() => {
                              setCustomerName(c.name); setCustomerPhone(c.phone); setShowSuggestions(false); setSelectedCustomerId(c.id)
                              fetch(`/api/loyalty/check?customerId=${c.id}`).then(r => r.ok ? r.json() : null)
                                .then(data => { if (data && data.loyaltyEnabled) setLoyaltyInfo(data); else setLoyaltyInfo(null) })
                                .catch(() => setLoyaltyInfo(null))
                            }}
                            className="w-full text-left px-3 py-1.5 text-sm hover:bg-gray-100 dark:hover:bg-gray-700 border-b last:border-b-0 border-gray-100 dark:border-gray-700">
                            <span className="font-medium">{c.name}</span>
                            <span className="text-gray-400 ml-1 text-xs">{c.phone}</span>
                          </button>
                        ))}
                      </div>
                    )}
                  </div>
                  <input type="text" placeholder="Nama" value={customerName} onChange={(e) => setCustomerName(e.target.value)} className="input-field text-sm" />
                </div>

                {/* Notes — single line */}
                <input type="text" placeholder="Catatan (opsional)" value={notes} onChange={(e) => setNotes(e.target.value)}
                  className="input-field text-sm dark:bg-gray-800 dark:border-gray-600 dark:text-white" />

                {/* Loyalty */}
                {loyaltyInfo && loyaltyInfo.loyaltyPoints > 0 && !appliedPromo && (
                  loyaltyDiscount > 0 ? (
                    <div className="flex items-center justify-between bg-purple-50 dark:bg-purple-900/20 rounded-lg px-3 py-2">
                      <div>
                        <p className="text-sm font-medium text-purple-700 dark:text-purple-300">🎁 {loyaltyPointsToRedeem} poin</p>
                        <p className="text-xs text-purple-600 dark:text-purple-400">Diskon {formatCurrency(loyaltyDiscount)}</p>
                      </div>
                      <button type="button" onClick={() => { setLoyaltyPointsToRedeem(0); setLoyaltyDiscount(0) }} className="text-red-500 text-xs">Hapus</button>
                    </div>
                  ) : (
                    <button type="button" onClick={() => setShowLoyaltyModal(true)}
                      className="w-full flex items-center justify-between px-3 py-2 rounded-lg border border-purple-300 dark:border-purple-700 hover:bg-purple-50 dark:hover:bg-purple-900/20 transition-colors">
                      <span className="text-sm font-medium text-purple-700 dark:text-purple-300">🏆 Gunakan Poin ({loyaltyInfo.loyaltyPoints} poin)</span>
                      <span className="text-purple-500 text-xs">→</span>
                    </button>
                  )
                )}
              </>
              ) : (
              <>
                {/* Payment Detail Step — clean and focused */}
                <button onClick={() => setPaymentStep('select')} className="text-sm text-primary-600 hover:text-primary-700 dark:text-primary-400 flex items-center gap-1">
                  <ArrowLeft className="w-3.5 h-3.5" /> Ganti metode
                </button>

                <div className="bg-primary-50 dark:bg-primary-900/20 rounded-lg px-3 py-2">
                  <p className="text-sm font-medium text-primary-700 dark:text-primary-300 flex items-center gap-2">
                    {selectedPaymentMethod === 'cash' && <><Wallet className="w-4 h-4" /> Pembayaran Cash</>}
                    {selectedPaymentMethod === 'card' && <><CreditCard className="w-4 h-4" /> Pembayaran Kartu</>}
                    {selectedPaymentMethod === 'qris' && <><Receipt className="w-4 h-4" /> Pembayaran QRIS</>}
                    {selectedPaymentMethod === 'transfer' && <><HandCoins className="w-4 h-4" /> Pembayaran Transfer</>}
                  </p>
                </div>

                {selectedPaymentMethod === 'cash' ? (
                  <>
                    <div>
                      <label className="block text-sm font-medium text-gray-700 dark:text-gray-200 mb-1">Uang Diterima</label>
                      <input type="number" className="input-field text-lg font-bold" placeholder="0" value={cashReceived}
                        onChange={(e) => setCashReceived(e.target.value)} autoFocus min={0} />
                    </div>
                    <div className="grid grid-cols-3 gap-1.5">
                      {(() => {
                        const suggestions: number[] = []
                        const rounded = Math.ceil(total / 1000) * 1000
                        if (rounded === total) suggestions.push(total); else suggestions.push(rounded)
                        const r5k = Math.ceil(total / 5000) * 5000
                        if (!suggestions.includes(r5k)) suggestions.push(r5k)
                        const r10k = Math.ceil(total / 10000) * 10000
                        if (!suggestions.includes(r10k)) suggestions.push(r10k)
                        const r50k = Math.ceil(total / 50000) * 50000
                        if (!suggestions.includes(r50k) && suggestions.length < 6) suggestions.push(r50k)
                        const r100k = Math.ceil(total / 100000) * 100000
                        if (!suggestions.includes(r100k) && suggestions.length < 6) suggestions.push(r100k)
                        return suggestions.slice(0, 6)
                      })().map(amount => (
                        <button key={amount} onClick={() => setCashReceived(String(amount))}
                          className={`py-2 rounded-lg text-xs font-medium border transition-colors ${
                            cashReceived === String(amount)
                              ? 'border-primary-500 bg-primary-50 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300'
                              : 'border-gray-200 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:border-gray-300'
                          }`}>{formatCurrency(amount)}</button>
                      ))}
                    </div>
                    {parseFloat(cashReceived) >= total && (
                      <div className="bg-green-50 dark:bg-green-900/20 rounded-lg px-3 py-2.5 flex justify-between items-center">
                        <span className="text-sm text-green-700 dark:text-green-300 font-medium">Kembalian</span>
                        <span className="text-xl font-bold text-green-700 dark:text-green-300">{formatCurrency(parseFloat(cashReceived) - total)}</span>
                      </div>
                    )}
                  </>
                ) : (
                  <div>
                    <label className="block text-sm font-medium text-gray-700 dark:text-gray-200 mb-1">Kode Approval / Referensi</label>
                    <input type="text" className="input-field"
                      placeholder={selectedPaymentMethod === 'qris' ? 'Kode dari mesin EDC / app' : selectedPaymentMethod === 'card' ? 'No. approval kartu' : 'No. referensi transfer'}
                      value={approvalCode} onChange={(e) => setApprovalCode(e.target.value)} autoFocus />
                  </div>
                )}
              </>
              )}
            </div>

            {/* ── Sticky Footer: Payment Buttons ── */}
            <div className="flex-shrink-0 px-4 py-3 border-t border-gray-100 dark:border-gray-700 bg-white dark:bg-gray-800">
              {paymentStep === 'select' ? (
                <div className="space-y-2">
                  <div className="grid grid-cols-4 gap-1.5">
                    {[
                      { key: 'cash', label: 'Cash', icon: Wallet },
                      { key: 'card', label: 'Kartu', icon: CreditCard },
                      { key: 'qris', label: 'QRIS', icon: Receipt },
                      { key: 'transfer', label: 'Transfer', icon: HandCoins },
                    ].map(method => (
                      <button key={method.key} onClick={() => handleSelectPaymentMethod(method.key)} disabled={submitting || onlinePaymentLoading}
                        className="btn-primary flex flex-col items-center justify-center gap-0.5 py-2.5 text-xs">
                        <method.icon className="w-4 h-4" /> {method.label}
                      </button>
                    ))}
                  </div>
                  {hasOnlinePayment && isOnline && (
                    <>
                      <div className="grid grid-cols-2 gap-1.5">
                        <button onClick={() => handleOnlinePayment('qris', 'qris')} disabled={submitting || onlinePaymentLoading}
                          className="py-2 rounded-lg text-xs font-medium flex items-center justify-center gap-1.5 bg-green-600 hover:bg-green-700 text-white transition-colors">
                          {onlinePaymentLoading ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <><QrCode className="w-3.5 h-3.5" /> QRIS Online</>}
                        </button>
                        <button onClick={() => setShowVABankSelect(true)} disabled={submitting || onlinePaymentLoading}
                          className="py-2 rounded-lg text-xs font-medium flex items-center justify-center gap-1.5 bg-indigo-600 hover:bg-indigo-700 text-white transition-colors">
                          {onlinePaymentLoading ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <><Building2 className="w-3.5 h-3.5" /> VA Online</>}
                        </button>
                      </div>
                      {showVABankSelect && (
                        <div className="grid grid-cols-3 gap-1.5">
                          {[
                            { code: 'bca', label: 'BCA' }, { code: 'bni', label: 'BNI' }, { code: 'bri', label: 'BRI' },
                            { code: 'mandiri', label: 'Mandiri' }, { code: 'cimb', label: 'CIMB' }, { code: 'permata', label: 'Permata' },
                          ].map(bank => (
                            <button key={bank.code} onClick={() => handleOnlinePayment('va', bank.code)} disabled={onlinePaymentLoading}
                              className="py-1.5 rounded-lg text-xs font-medium bg-indigo-50 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300 border border-indigo-200 dark:border-indigo-800 hover:bg-indigo-100 dark:hover:bg-indigo-900/50 transition-colors">
                              {bank.label}
                            </button>
                          ))}
                        </div>
                      )}
                    </>
                  )}
                </div>
              ) : (
                <button onClick={handleConfirmPayment}
                  disabled={submitting || (selectedPaymentMethod === 'cash' ? !cashReceived || parseFloat(cashReceived) < total : !approvalCode.trim())}
                  className="w-full btn-primary py-3 text-base font-semibold flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed">
                  {submitting ? <Loader2 className="w-5 h-5 animate-spin" /> : <><CheckCircle2 className="w-5 h-5" /> Konfirmasi Pembayaran</>}
                </button>
              )}
            </div>

          </div>
        </div>
      )}

      {/* Payment Orders Panel (from QR scan customers) */}
      {showPaymentOrders && (() => {
        const q = paymentSearchQuery.toLowerCase().trim()
        const filteredPaymentOrders = q
          ? paymentOrders.filter(o =>
              (o.customerName && o.customerName.toLowerCase().includes(q)) ||
              (o.table?.number && String(o.table.number) === q) ||
              (o.orderNumber && o.orderNumber.toLowerCase().includes(q))
            )
          : paymentOrders
        return (
        <div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center bg-black/50 p-4">
          <div className="bg-white dark:bg-gray-800 rounded-xl w-full max-w-lg max-h-[80vh] overflow-hidden flex flex-col">
            <div className="p-4 border-b border-gray-200 dark:border-gray-700 flex-shrink-0 space-y-3">
              <div className="flex items-center justify-between">
                <h3 className="text-lg font-semibold dark:text-white flex items-center gap-2">
                  <HandCoins className="w-5 h-5 text-yellow-600" /> Pembayaran di Kasir
                  <span className="badge bg-yellow-100 dark:bg-yellow-900/30 text-yellow-700 dark:text-yellow-300">{paymentOrders.length}</span>
                </h3>
                <button onClick={() => setShowPaymentOrders(false)}><X className="w-5 h-5 text-gray-400 dark:text-gray-500" /></button>
              </div>
              <div className="relative">
                <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400 dark:text-gray-500" />
                <input
                  type="text"
                  placeholder="Cari nama, nomor meja, atau nomor order..."
                  className="input-field pl-9 text-sm dark:bg-gray-800 dark:border-gray-600 dark:text-white"
                  value={paymentSearchQuery}
                  onChange={(e) => setPaymentSearchQuery(e.target.value)}
                  autoFocus
                />
              </div>
            </div>
            <div className="flex-1 overflow-y-auto p-4 space-y-4">
              {filteredPaymentOrders.length === 0 ? (
                <p className="text-center text-gray-500 dark:text-gray-400 py-8">
                  {q ? 'Tidak ditemukan pesanan yang cocok' : 'Tidak ada order menunggu pembayaran'}
                </p>
              ) : (
                filteredPaymentOrders.map(order => (
                  <div key={order.id} className="border border-yellow-200 dark:border-yellow-800 rounded-xl p-4 bg-yellow-50 dark:bg-yellow-900/30">
                    <div className="flex items-start justify-between mb-2">
                      <div>
                        <span className="font-mono text-sm font-bold dark:text-white">{order.orderNumber}</span>
                        <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
                          {order.table && <span className="font-medium text-blue-700 dark:text-blue-400">Meja {order.table.number}</span>}
                          {order.table && order.customerName && <span> &bull; </span>}
                          <span className="font-medium dark:text-gray-300">{order.customerName || 'Customer'}</span>
                          <span className={`ml-2 px-1.5 py-0.5 rounded text-xs font-medium ${order.orderType === 'takeaway' ? 'bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300' : 'bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300'}`}>
                            {order.orderType === 'takeaway' ? 'Takeaway' : 'Dine-in'}
                          </span>
                        </div>
                      </div>
                      <span className="font-bold text-lg dark:text-white">{formatCurrency(order.total)}</span>
                    </div>
                    <div className="text-xs text-gray-600 dark:text-gray-300 mb-3">
                      {order.items?.map((item: any, idx: number) => (
                        <span key={idx}>{idx > 0 && ', '}{item.quantity}x {item.menuItem?.name}</span>
                      ))}
                    </div>
                    {/* Payment method selection or detail input */}
                    {payingOrderId === order.id && paymentStep === 'detail' ? (
                      <div className="space-y-2 border-t border-yellow-200 dark:border-yellow-700 pt-3 mt-2">
                        <div className="flex items-center justify-between">
                          <span className="text-xs font-medium text-gray-700 dark:text-gray-300 capitalize flex items-center gap-1">
                            {selectedPaymentMethod === 'cash' && <><Wallet className="w-3.5 h-3.5" /> Cash</>}
                            {selectedPaymentMethod === 'card' && <><CreditCard className="w-3.5 h-3.5" /> Kartu</>}
                            {selectedPaymentMethod === 'qris' && <><Receipt className="w-3.5 h-3.5" /> QRIS</>}
                            {selectedPaymentMethod === 'transfer' && <><HandCoins className="w-3.5 h-3.5" /> Transfer</>}
                          </span>
                          <button onClick={() => { setPayingOrderId(null); setPaymentStep('select') }}
                            className="text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400">Ganti</button>
                        </div>
                        {selectedPaymentMethod === 'cash' ? (
                          <>
                            <input type="number" className="input-field text-sm font-bold" placeholder="Uang diterima"
                              value={cashReceived} onChange={(e) => setCashReceived(e.target.value)} autoFocus min={0} />
                            <div className="grid grid-cols-3 gap-1">
                              {(() => {
                                const t = Number(order.total)
                                const suggestions: number[] = []
                                const r1k = Math.ceil(t / 1000) * 1000
                                if (r1k === t) suggestions.push(t); else suggestions.push(r1k)
                                const r5k = Math.ceil(t / 5000) * 5000
                                if (!suggestions.includes(r5k)) suggestions.push(r5k)
                                const r10k = Math.ceil(t / 10000) * 10000
                                if (!suggestions.includes(r10k)) suggestions.push(r10k)
                                return suggestions.slice(0, 3)
                              })().map(amount => (
                                <button key={amount} onClick={() => setCashReceived(String(amount))}
                                  className={`py-1 rounded text-xs font-medium border transition-colors ${
                                    cashReceived === String(amount)
                                      ? 'border-primary-500 bg-primary-50 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300'
                                      : 'border-gray-200 dark:border-gray-600 text-gray-600 dark:text-gray-300'
                                  }`}>{formatCurrency(amount)}</button>
                              ))}
                            </div>
                            {parseFloat(cashReceived) >= Number(order.total) && (
                              <div className="flex justify-between text-xs bg-green-50 dark:bg-green-900/20 rounded px-2 py-1">
                                <span className="text-green-700 dark:text-green-300">Kembalian</span>
                                <span className="font-bold text-green-700 dark:text-green-300">{formatCurrency(parseFloat(cashReceived) - Number(order.total))}</span>
                              </div>
                            )}
                          </>
                        ) : (
                          <input type="text" className="input-field text-sm" placeholder="Kode approval / referensi"
                            value={approvalCode} onChange={(e) => setApprovalCode(e.target.value)} autoFocus />
                        )}
                        <button onClick={handleConfirmExistingPayment}
                          disabled={selectedPaymentMethod === 'cash' ? !cashReceived || parseFloat(cashReceived) < Number(order.total) : !approvalCode.trim()}
                          className="w-full py-1.5 rounded-lg text-xs font-medium bg-green-600 hover:bg-green-700 text-white flex items-center justify-center gap-1 disabled:opacity-50 disabled:cursor-not-allowed">
                          <CheckCircle2 className="w-3.5 h-3.5" /> Konfirmasi
                        </button>
                      </div>
                    ) : (
                    <div className="grid grid-cols-4 gap-1.5">
                      {[
                        { key: 'cash', label: 'Cash' },
                        { key: 'card', label: 'Kartu' },
                        { key: 'qris', label: 'QRIS' },
                        { key: 'transfer', label: 'Transfer' },
                      ].map(method => (
                        <button key={method.key} onClick={() => handleSelectPaymentForExisting(order.id, Number(order.total), method.key)}
                          className="py-1.5 rounded-lg text-xs font-medium bg-primary-600 hover:bg-primary-700 text-white">
                          {method.label}
                        </button>
                      ))}
                    </div>
                    )}
                  </div>
                ))
              )}
            </div>
          </div>
        </div>
        )
      })()}

      {/* Notifications Panel */}
      {showNotifications && (
        <div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center bg-black/50 p-4">
          <div className="bg-white dark:bg-gray-800 rounded-xl w-full max-w-lg max-h-[80vh] overflow-hidden flex flex-col">
            <div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700 flex-shrink-0">
              <h3 className="text-lg font-semibold dark:text-white flex items-center gap-2">
                <Bell className="w-5 h-5" /> Notifikasi
                <span className="badge bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300">{unreadCount}</span>
              </h3>
              <button onClick={() => setShowNotifications(false)}><X className="w-5 h-5 text-gray-400 dark:text-gray-500" /></button>
            </div>
            <div className="flex-1 overflow-y-auto p-4 space-y-3">
              {notifications.length === 0 ? (
                <p className="text-center text-gray-500 dark:text-gray-400 py-8">Tidak ada notifikasi baru</p>
              ) : (
                notifications.map(notif => (
                  <div key={notif.id} className={`rounded-lg p-3 border ${
                    notif.type === 'call_waiter' ? 'border-red-200 dark:border-red-800 bg-red-50 dark:bg-red-900/30' :
                    notif.type === 'call_payment' || notif.type === 'payment_request' ? 'border-yellow-200 dark:border-yellow-800 bg-yellow-50 dark:bg-yellow-900/30' :
                    'border-blue-200 dark:border-blue-800 bg-blue-50 dark:bg-blue-900/30'
                  }`}>
                    <div className="flex items-start justify-between">
                      <div>
                        <p className="font-semibold text-sm dark:text-white">{notif.title}</p>
                        <p className="text-xs text-gray-600 dark:text-gray-300 mt-0.5">{notif.message}</p>
                        <p className="text-xs text-gray-400 dark:text-gray-500 mt-1">{new Date(notif.createdAt).toLocaleString('id-ID', { hour: '2-digit', minute: '2-digit' })}</p>
                      </div>
                      <button onClick={() => handleDismissNotif(notif.id)}
                        className="text-xs bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 px-2 py-1 rounded font-medium dark:text-gray-200">
                        OK
                      </button>
                    </div>
                  </div>
                ))
              )}
            </div>
          </div>
        </div>
      )}

      {/* Online Payment Modal */}
      {showOnlinePayment && onlinePaymentData && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4">
          <div className="bg-white dark:bg-gray-800 rounded-xl w-full max-w-sm p-6">
            <div className="flex items-center justify-between mb-4">
              <h3 className="text-lg font-semibold dark:text-white">Menunggu Pembayaran</h3>
              <button onClick={() => { setShowOnlinePayment(false); setOnlinePaymentData(null) }}><X className="w-5 h-5 text-gray-400 dark:text-gray-500" /></button>
            </div>

            <div className="text-center mb-4">
              <p className="text-sm text-gray-500 dark:text-gray-400">Order</p>
              <p className="text-lg font-bold font-mono text-primary-600">{onlinePaymentData.orderNumber}</p>
              <p className="text-xl font-bold mt-1 dark:text-white">{formatCurrency(onlinePaymentData.amount)}</p>
            </div>

            {onlinePaymentData.paymentMethod === 'qris' ? (
              <div className="text-center mb-4">
                <p className="text-sm font-medium text-gray-700 dark:text-gray-200 mb-3">Scan QR Code</p>
                {onlinePaymentData.qrisUrl ? (
                  <div className="bg-white border-2 border-gray-200 dark:border-gray-600 rounded-xl p-4 inline-block">
                    <img src={onlinePaymentData.qrisUrl} alt="QRIS" className="w-48 h-48 mx-auto" />
                  </div>
                ) : onlinePaymentData.paymentNo ? (
                  <div className="bg-white border-2 border-gray-200 dark:border-gray-600 rounded-xl p-4 inline-block">
                    <QRCodeSVG value={onlinePaymentData.paymentNo} size={192} level="M" />
                  </div>
                ) : null}
              </div>
            ) : (
              <div className="mb-4">
                <p className="text-sm font-medium text-gray-700 dark:text-gray-200 mb-2 text-center">
                  Transfer ke VA {onlinePaymentData.paymentChannel?.toUpperCase()}
                </p>
                <div className="bg-gray-50 dark:bg-gray-900 border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-xl p-4 text-center mb-3">
                  <p className="text-2xl font-bold font-mono tracking-wider dark:text-white">{onlinePaymentData.paymentNo || '-'}</p>
                </div>
                <button
                  onClick={() => {
                    if (onlinePaymentData.paymentNo) {
                      navigator.clipboard.writeText(onlinePaymentData.paymentNo)
                      toast.success('Nomor VA disalin!')
                    }
                  }}
                  className="w-full py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm font-medium text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 flex items-center justify-center gap-2"
                >
                  <Copy className="w-4 h-4" /> Salin Nomor VA
                </button>
              </div>
            )}

            <div className="flex items-center justify-center gap-2 text-sm text-gray-500 dark:text-gray-400 mb-3">
              <Loader2 className="w-4 h-4 animate-spin" />
              <span>Menunggu pembayaran...</span>
            </div>

            {onlinePaymentData.expired && (
              <div className="flex items-center justify-center gap-1 text-xs text-red-600 dark:text-red-400">
                <Clock className="w-3 h-3" />
                <span>Expired: {new Date(onlinePaymentData.expired).toLocaleString('id-ID')}</span>
              </div>
            )}
          </div>
        </div>
      )}

      {/* Loyalty Redemption Modal */}
      {showLoyaltyModal && loyaltyInfo && (
        <div className="fixed inset-0 z-[60] flex items-center justify-center bg-black/50 p-4">
          <div className="bg-white dark:bg-gray-800 rounded-xl w-full max-w-sm p-6">
            <h3 className="text-lg font-bold mb-4 dark:text-white">Gunakan Poin Loyalti</h3>
            <div className="space-y-3">
              <div className="bg-purple-50 dark:bg-purple-900/20 rounded-lg p-3 text-center">
                <p className="text-2xl font-bold text-purple-700 dark:text-purple-300">{loyaltyInfo.loyaltyPoints}</p>
                <p className="text-sm text-purple-600 dark:text-purple-400">Poin tersedia • {loyaltyInfo.tier}</p>
              </div>
              <div>
                <label className="block text-sm font-medium text-gray-700 dark:text-gray-200 mb-1">Jumlah poin</label>
                <input
                  type="number"
                  min={loyaltyInfo.minRedemption}
                  max={loyaltyInfo.maxRedemption > 0 ? Math.min(loyaltyInfo.maxRedemption, loyaltyInfo.loyaltyPoints) : loyaltyInfo.loyaltyPoints}
                  value={loyaltyPointsToRedeem || ''}
                  onChange={(e) => setLoyaltyPointsToRedeem(parseInt(e.target.value) || 0)}
                  className="input-field"
                  placeholder={`Min. ${loyaltyInfo.minRedemption} poin`}
                />
              </div>
              <div className="flex gap-2">
                <button type="button" onClick={() => setLoyaltyPointsToRedeem(loyaltyInfo.minRedemption)}
                  className="btn-secondary text-xs px-2 py-1">{loyaltyInfo.minRedemption} poin</button>
                <button type="button" onClick={() => setLoyaltyPointsToRedeem(Math.min(50, loyaltyInfo.loyaltyPoints))}
                  className="btn-secondary text-xs px-2 py-1">50 poin</button>
                <button type="button" onClick={() => setLoyaltyPointsToRedeem(loyaltyInfo.loyaltyPoints)}
                  className="btn-secondary text-xs px-2 py-1">Semua</button>
              </div>
              {loyaltyPointsToRedeem > 0 && (
                <div className="bg-green-50 dark:bg-green-900/20 rounded-lg p-2 text-center">
                  <p className="text-sm text-green-700 dark:text-green-300">
                    {loyaltyPointsToRedeem} poin = <span className="font-bold">{formatCurrency(loyaltyPointsToRedeem * loyaltyInfo.redemptionValue)}</span> diskon
                  </p>
                </div>
              )}
              <div className="flex gap-2 mt-4">
                <button type="button" onClick={() => { setShowLoyaltyModal(false); setLoyaltyPointsToRedeem(0) }}
                  className="btn-secondary flex-1">Batal</button>
                <button type="button"
                  disabled={loyaltyPointsToRedeem < loyaltyInfo.minRedemption || loyaltyPointsToRedeem > loyaltyInfo.loyaltyPoints}
                  onClick={() => {
                    const disc = loyaltyPointsToRedeem * loyaltyInfo.redemptionValue
                    setLoyaltyDiscount(Math.min(disc, subtotal))
                    setShowLoyaltyModal(false)
                  }}
                  className="btn-primary flex-1 disabled:opacity-50">Terapkan</button>
              </div>
            </div>
          </div>
        </div>
      )}

      {/* Order Success + Print */}
      {showOrderSuccess && lastOrder && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4">
          <div className="bg-white dark:bg-gray-800 rounded-xl w-full max-w-sm p-6 text-center">
            <div className={`w-16 h-16 ${lastOrder.offline ? 'bg-orange-100 dark:bg-orange-900/30' : 'bg-green-100 dark:bg-green-900/30'} rounded-full flex items-center justify-center mx-auto mb-4`}>
              {lastOrder.offline ? <WifiOff className="w-8 h-8 text-orange-600" /> : <CheckCircle2 className="w-8 h-8 text-green-600" />}
            </div>
            <h3 className="text-xl font-bold text-gray-900 dark:text-white mb-1">
              {lastOrder.offline ? 'Disimpan Offline' : 'Pesanan Berhasil!'}
            </h3>
            {posOrderFlow === 'cashier_first' && !lastOrder.offline && (
              <p className="text-xs text-gray-500 dark:text-gray-400 mb-1">Nomor Antrian</p>
            )}
            <p className={`font-mono font-bold text-primary-600 mb-2 ${posOrderFlow === 'cashier_first' ? 'text-4xl' : 'text-2xl'}`}>{lastOrder.orderNumber}</p>
            {lastOrder.offline && (
              <p className="text-xs text-orange-600 dark:text-orange-400 mb-2">Akan otomatis dikirim saat koneksi kembali</p>
            )}
            <div className="text-sm text-gray-600 dark:text-gray-300 mb-4">
              Total: <span className="font-bold">{formatCurrency(lastOrder.total)}</span>
            </div>

            {/* Assign table — cashier_first mode */}
            {posOrderFlow === 'cashier_first' && !lastOrder.offline && lastOrder.orderType !== 'takeaway' && (
              <div className="mb-4">
                {lastOrder.table ? (
                  <div className="bg-blue-50 dark:bg-blue-900/20 rounded-lg px-3 py-2 text-sm text-blue-700 dark:text-blue-300">
                    Meja: <span className="font-bold">{lastOrder.table.name || `Meja ${lastOrder.table.number}`}</span>
                  </div>
                ) : (
                  <div className="flex gap-2">
                    <select
                      className="input-field text-sm flex-1 dark:bg-gray-700 dark:border-gray-600 dark:text-white"
                      value={assignTableValue}
                      onChange={(e) => setAssignTableValue(e.target.value)}
                    >
                      <option value="">Pilih Meja...</option>
                      {tables.map(t => <option key={t.id} value={t.id}>{t.name || `Meja ${t.number}`}</option>)}
                    </select>
                    <button
                      onClick={async () => {
                        if (!assignTableValue) { toast.error('Pilih meja'); return }
                        try {
                          const res = await fetch(`/api/orders/${lastOrder.id}`, {
                            method: 'PUT',
                            headers: { 'Content-Type': 'application/json' },
                            body: JSON.stringify({ tableId: assignTableValue }),
                          })
                          if (!res.ok) throw new Error('Gagal assign meja')
                          const data = await res.json()
                          setLastOrder(data)
                          setAssignTableValue('')
                          toast.success('Meja berhasil di-assign!')
                        } catch (e: any) {
                          toast.error(e.message || 'Gagal assign meja')
                        }
                      }}
                      className="btn-primary px-3 py-1.5 text-sm"
                    >
                      Assign
                    </button>
                  </div>
                )}
              </div>
            )}

            {!lastOrder.offline && (
            <div className="grid grid-cols-2 gap-2 mb-3">
              <button
                onClick={async () => {
                  try {
                    const store = stores.find((s: any) => s.id === selectedStore)
                    const fbUrl = printerSettings.receipt_feedback_qr === 'true' && lastOrder.feedbackToken ? `${window.location.origin}/f/${lastOrder.feedbackToken}` : null
                    const receiptData = orderToReceiptData(lastOrder, authUser?.tenant?.name || store?.name || '-', store?.name || '', { feedbackUrl: fbUrl, taxRate, serviceChargeRate: scRate })
                    const showPopup = printerSettings.receipt_show_browser_popup !== 'false'
                    const result = await printReceipt(receiptData, 'customer', thermalOpts, receiptTemplate, showPopup)
                    if (result.success) toast.success(result.method === 'thermal' ? 'Nota terkirim ke printer' : 'Mencetak nota...')
                    else toast.error(result.error || 'Gagal cetak. Hubungkan ulang printer.')
                  } catch (err: any) {
                    toast.error('Error: ' + (err?.message || 'Gagal cetak'))
                  }
                }}
                className="btn-primary flex items-center justify-center gap-2"
              >
                <Printer className="w-4 h-4" /> Cetak Nota
              </button>
              <button
                onClick={async () => {
                  try {
                    const store = stores.find((s: any) => s.id === selectedStore)
                    const receiptData = orderToReceiptData(lastOrder, authUser?.tenant?.name || store?.name || '-', store?.name || '', { taxRate, serviceChargeRate: scRate })
                    const showPopup = printerSettings.receipt_show_browser_popup !== 'false'
                    const result = await printReceipt(receiptData, 'kitchen', thermalOpts, receiptTemplate, showPopup)
                    if (result.success) toast.success(result.method === 'thermal' ? 'Tiket dapur terkirim ke printer' : 'Mencetak tiket dapur...')
                    else toast.error(result.error || 'Gagal cetak. Hubungkan ulang printer.')
                  } catch (err: any) {
                    toast.error('Error: ' + (err?.message || 'Gagal cetak'))
                  }
                }}
                className="btn-ghost border border-gray-300 dark:border-gray-600 flex items-center justify-center gap-2"
              >
                <Printer className="w-4 h-4" /> Cetak Dapur
              </button>
            </div>
            )}
            <button
              onClick={() => { setShowOrderSuccess(false); setLastOrder(null); setAssignTableValue('') }}
              className="text-gray-500 dark:text-gray-400 text-sm hover:text-gray-700 dark:hover:text-gray-200"
            >
              Tutup
            </button>
          </div>
        </div>
      )}
    </div>
  )
}
