"use client";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useRouter, useSearchParams, usePathname } from "next/navigation";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { useTranslations, useLocale } from "next-intl";
import {
  ChevronLeft,
  ChevronRight,
  Minus,
  Package,
  Plus,
  Search,
  ShoppingCart,
  Trash2,
  UtensilsCrossed,
  Users,
  Video,
  X,
} from "lucide-react";
import { apiGet, apiPatch, apiPost, ApiClientError } from "@/lib/api/client";
import type {
  MenuCategory,
  MenuItem,
  Order,
  Table,
  TableBoardItem,
  QueueTicket,
} from "@/lib/api/types";
import { useAuthStore } from "@/lib/stores/auth.store";
import { useCafeSettings } from "@/lib/hooks/use-cafe-settings";
import { useCartStore, type CartItem } from "@/lib/stores/cart.store";
import type { OrderType } from "@/lib/stores/cart.store";
import { formatCurrency, formatNumber } from "@/lib/format";
import { formatOrderNumber } from "@/lib/order-number";
import { iranMobileForApi } from "@/lib/phone";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { useIsRtl } from "@/lib/use-is-rtl";
import { useBranchStore } from "@/lib/stores/branch.store";
import { getOrCreateTerminalId } from "@/lib/terminal";
import { MenuItemLabels } from "@/components/menu/menu-item-labels";
import { CategoryVisual } from "@/components/menu/category-visual";
import { getMenuPrimaryName, menuItemMatchesSearch } from "@/lib/menu-display";
import { Input } from "@/components/ui/input";
import { LabeledField } from "@/components/ui/labeled-field";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";
import { MenuItemMedia } from "@/components/menu/menu-item-media";
import {
  buildCategoryNameMap,
  inferMenuItemKind,
} from "@/lib/menu-item-image";
import { PosPayPanel } from "@/components/pos/pos-pay-panel";
import { PosTableBoard } from "@/components/pos/pos-table-board";
import { PosCustomerPicker } from "@/components/pos/pos-customer-picker";
import { PosSlipModal, type KitchenSlipLine } from "@/components/pos/pos-slip-modal";
import { PosQueueBar } from "@/components/pos/pos-queue-bar";
import {
  branchMenuItemToMenuItem,
  getBranchMenu,
} from "@/lib/api/branch-menu";
import { requestPosPayment, posDeviceErrorMessage } from "@/lib/api/pos-device";
import { orderAmountDue, submitOrderToApi, isLocalOrder } from "@/lib/pos/submit-order";
import { useSyncQueueStore } from "@/lib/stores/sync-queue.store";
import { useConfirm } from "@/components/providers/confirm-provider";

const TAX_RATE = 0.09;

function buildKitchenLines(
  pending: { menuItemId: string; quantity: number; notes?: string }[],
  cartItems: CartItem[]
): KitchenSlipLine[] {
  return pending.map((p) => {
    const line = cartItems.find((i) => i.menuItem.id === p.menuItemId);
    return {
      name: line?.menuItem.name ?? p.menuItemId,
      quantity: p.quantity,
      notes: p.notes,
    };
  });
}

function cartToKitchenLines(cartItems: CartItem[]): KitchenSlipLine[] {
  return cartItems
    .filter((i) => !i.isVoided && i.quantity > 0)
    .map((i) => ({
      name: i.menuItem.name,
      quantity: i.quantity,
      notes: i.notes,
    }));
}

// ─── Order Type Picker ───────────────────────────────────────────────────────

function OrderTypePicker({
  onSelect,
  t,
}: {
  onSelect: (type: OrderType) => void;
  t: ReturnType<typeof useTranslations<"pos">>;
}) {
  return (
    <div className="flex flex-1 flex-col items-center justify-center gap-8 px-4 py-10">
      <div className="text-center">
        <h2 className="text-2xl font-bold tracking-tight">
          {t("orderTypePicker")}
        </h2>
      </div>

      <div className="grid w-full max-w-xl grid-cols-3 gap-3 sm:gap-4">
        {/* Table */}
        <button
          type="button"
          onClick={() => onSelect("table")}
          className="group flex cursor-pointer flex-col items-center gap-3 rounded-2xl border-2 border-border bg-card p-5 shadow-sm transition-all hover:border-primary hover:shadow-md active:scale-[0.97]"
        >
          <div className="rounded-xl bg-primary/10 p-3.5 transition-colors group-hover:bg-primary/20">
            <UtensilsCrossed className="size-8 text-primary" />
          </div>
          <div className="text-center">
            <p className="text-sm font-semibold sm:text-base">
              {t("orderTypeTable")}
            </p>
            <p className="mt-0.5 text-[11px] text-muted-foreground">
              {t("orderTypeTableDesc")}
            </p>
          </div>
        </button>

        {/* Counter */}
        <button
          type="button"
          onClick={() => onSelect("counter")}
          className="group flex cursor-pointer flex-col items-center gap-3 rounded-2xl border-2 border-border bg-card p-5 shadow-sm transition-all hover:border-blue-500 hover:shadow-md active:scale-[0.97]"
        >
          <div className="rounded-xl bg-blue-500/10 p-3.5 transition-colors group-hover:bg-blue-500/20">
            <Users className="size-8 text-blue-600" />
          </div>
          <div className="text-center">
            <p className="text-sm font-semibold sm:text-base">
              {t("orderTypeCounter")}
            </p>
            <p className="mt-0.5 text-[11px] text-muted-foreground">
              {t("orderTypeCounterDesc")}
            </p>
          </div>
        </button>

        {/* Takeaway */}
        <button
          type="button"
          onClick={() => onSelect("takeaway")}
          className="group flex cursor-pointer flex-col items-center gap-3 rounded-2xl border-2 border-border bg-card p-5 shadow-sm transition-all hover:border-amber-500 hover:shadow-md active:scale-[0.97]"
        >
          <div className="rounded-xl bg-amber-500/10 p-3.5 transition-colors group-hover:bg-amber-500/20">
            <Package className="size-8 text-amber-600" />
          </div>
          <div className="text-center">
            <p className="text-sm font-semibold sm:text-base">
              {t("orderTypeTakeaway")}
            </p>
            <p className="mt-0.5 text-[11px] text-muted-foreground">
              {t("orderTypeTakeawayDesc")}
            </p>
          </div>
        </button>
      </div>
    </div>
  );
}

// ─── Order Type Badge ─────────────────────────────────────────────────────────

function OrderTypeBadge({
  orderType,
  tableNumber,
  onClick,
  t,
}: {
  orderType: OrderType;
  tableNumber?: number | string | null;
  onClick?: () => void;
  t: ReturnType<typeof useTranslations<"pos">>;
}) {
  const label =
    orderType === "table"
      ? `${t("table")} ${tableNumber ?? "—"}`
      : orderType === "counter"
        ? t("counterBadge")
        : t("takeawayBadge");

  const cls =
    orderType === "table"
      ? "border-primary bg-primary/10 text-primary hover:bg-primary/20"
      : orderType === "counter"
        ? "border-blue-400 bg-blue-50 text-blue-700 hover:bg-blue-100"
        : "border-amber-400 bg-amber-50 text-amber-700 hover:bg-amber-100";

  return (
    <button
      type="button"
      onClick={onClick}
      className={cn(
        "shrink-0 rounded-full border px-3 py-1 text-xs font-semibold transition-colors",
        cls,
        onClick ? "cursor-pointer" : "cursor-default"
      )}
    >
      {label}
    </button>
  );
}

// ─── Main Component ───────────────────────────────────────────────────────────

export function PosScreen() {
  const t = useTranslations("pos");
  const tQueue = useTranslations("queue");
  const tErrors = useTranslations("errors");
  const tCommon = useTranslations("common");
  const tDashboard = useTranslations("dashboard");
  const locale = useLocale();
  const isRtl = useIsRtl();
  const numberLocale = locale === "en" ? "en-US" : "fa-IR";
  const cafeId = useAuthStore((s) => s.user?.cafeId);
  const { data: cafeSettings } = useCafeSettings(cafeId);
  const cafeName = cafeSettings?.name ?? tDashboard("cafeName");
  const userRole = useAuthStore((s) => s.user?.role);
  const isManager = userRole === "Manager" || userRole === "Owner";
  const branchId = useBranchStore((s) => s.branchId);
  const setBranchId = useBranchStore((s) => s.setBranchId);
  const queryClient = useQueryClient();
  const confirmDialog = useConfirm();
  const isOnline = useSyncQueueStore((s) => s.isOnline);
  const router = useRouter();
  const pathname = usePathname();
  const searchParams = useSearchParams();
  const reservationId = searchParams.get("reservationId");
  const reservationGuest = searchParams.get("guestName");
  const urlOrderId = searchParams.get("orderId");

  const [kitchenSlip, setKitchenSlip] = useState<{
    lines: KitchenSlipLine[];
    orderId?: string;
    tableNumber?: string | number | null;
    guestName?: string | null;
  } | null>(null);
  const [posMode, setPosMode] = useState<"order" | "pay">("order");
  const [showTablePicker, setShowTablePicker] = useState(false);
  const [showTransferPicker, setShowTransferPicker] = useState(false);

  const {
    items,
    addItem,
    removeItem,
    updateQty,
    couponCode,
    appliedCoupon,
    setCouponCode,
    setAppliedCoupon,
    clearCoupon,
    tableId,
    setTableId,
    orderType,
    setOrderType,
    activeOrderId,
    activeOrderDisplayNumber,
    setActiveOrderId,
    customerId,
    guestName,
    setGuestName,
    guestPhone,
    setGuestPhone,
    setCustomer,
    clearCustomer,
    hydrateFromOrder,
    getPendingLines,
    clearCart,
    clearSession,
    subtotal,
  } = useCartStore();

  const syncUrl = useCallback(
    (tid: string | null, oid: string | null) => {
      const params = new URLSearchParams(searchParams.toString());
      if (tid) params.set("tableId", tid);
      else params.delete("tableId");
      if (oid) params.set("orderId", oid);
      else params.delete("orderId");
      const qs = params.toString();
      router.replace(qs ? `${pathname}?${qs}` : pathname, { scroll: false });
    },
    [pathname, router, searchParams]
  );

  // Restore tableId + infer orderType from URL params
  useEffect(() => {
    const tid = searchParams.get("tableId");
    if (tid) {
      setTableId(tid);
      if (!orderType) setOrderType("table");
    }
  }, [searchParams, setTableId, setOrderType, orderType]);

  useEffect(() => {
    if (urlOrderId) setActiveOrderId(urlOrderId);
  }, [urlOrderId, setActiveOrderId]);

  useEffect(() => {
    if (reservationGuest) setGuestName(reservationGuest);
  }, [reservationGuest, setGuestName]);

  useEffect(() => {
    if (!cafeId) return;
    apiPost(`/api/cafes/${cafeId}/terminals/register`, {
      terminalId: getOrCreateTerminalId(),
    }).catch(() => undefined);
  }, [cafeId]);

  const [selectedCategory, setSelectedCategory] = useState<string | "all">("all");
  const [itemSearch, setItemSearch] = useState("");
  const [orderMessage, setOrderMessage] = useState<string | null>(null);
  const [couponMessage, setCouponMessage] = useState<{
    type: "success" | "error";
    text: string;
  } | null>(null);

  const { data: branches = [] } = useQuery({
    queryKey: ["branches", cafeId],
    queryFn: () =>
      apiGet<{ id: string; name: string }[]>(`/api/cafes/${cafeId}/branches`),
    enabled: !!cafeId,
  });

  useEffect(() => {
    if (branches.length === 0) return;
    const valid = branchId && branches.some((b) => b.id === branchId);
    if (!valid) setBranchId(branches[0]!.id);
  }, [branches, branchId, setBranchId]);

  const orderBranchId = useMemo(() => {
    if (branches.length === 0) return null;
    if (branchId && branches.some((b) => b.id === branchId)) return branchId;
    return branches[0]?.id ?? null;
  }, [branchId, branches]);

  const { data: categories, isLoading: loadingCategories } = useQuery({
    queryKey: ["menu-categories", cafeId],
    queryFn: () => apiGet<MenuCategory[]>(`/api/cafes/${cafeId}/menu/categories`),
    enabled: !!cafeId,
  });

  const { data: globalMenuItems, isLoading: loadingGlobalItems } = useQuery({
    queryKey: ["menu-items", cafeId, selectedCategory],
    queryFn: () => {
      const qs =
        selectedCategory !== "all" ? `?categoryId=${selectedCategory}` : "";
      return apiGet<MenuItem[]>(`/api/cafes/${cafeId}/menu/items${qs}`);
    },
    enabled: !!cafeId && !orderBranchId,
  });

  const { data: branchMenuRows, isLoading: loadingBranchMenu } = useQuery({
    queryKey: ["branch-menu", cafeId, orderBranchId, selectedCategory],
    queryFn: () => getBranchMenu(cafeId!, orderBranchId!),
    enabled: !!cafeId && !!orderBranchId,
  });

  const menuItems = useMemo(() => {
    if (orderBranchId && branchMenuRows) {
      const mapped = branchMenuRows.map(branchMenuItemToMenuItem);
      if (selectedCategory === "all") return mapped;
      return mapped.filter((i) => i.categoryId === selectedCategory);
    }
    return globalMenuItems;
  }, [orderBranchId, branchMenuRows, globalMenuItems, selectedCategory]);

  const loadingItems = orderBranchId ? loadingBranchMenu : loadingGlobalItems;

  const { data: allMenuItems, isLoading: loadingAllCatalog } = useQuery({
    queryKey: ["branch-menu-all", cafeId, orderBranchId],
    queryFn: async () => {
      if (orderBranchId && cafeId) {
        const rows = await getBranchMenu(cafeId, orderBranchId);
        return rows.map(branchMenuItemToMenuItem);
      }
      return apiGet<MenuItem[]>(`/api/cafes/${cafeId}/menu/items`);
    },
    enabled: !!cafeId,
  });

  const menuById = useMemo(() => {
    const map = new Map<string, MenuItem>();
    for (const m of allMenuItems ?? menuItems ?? []) {
      map.set(m.id, m);
    }
    return map;
  }, [allMenuItems, menuItems]);

  // Hydrate from URL order
  useEffect(() => {
    if (!cafeId || !urlOrderId || menuById.size === 0) return;
    if (activeOrderId === urlOrderId && items.length > 0) return;
    apiGet<Order>(`/api/cafes/${cafeId}/orders/${urlOrderId}`)
      .then((order) => {
        hydrateFromOrder(order, menuById);
        if (order.tableId) {
          setTableId(order.tableId);
          setOrderType("table");
        } else if (!orderType) {
          setOrderType("counter");
        }
      })
      .catch(() => undefined);
  }, [
    cafeId,
    urlOrderId,
    menuById,
    activeOrderId,
    items.length,
    hydrateFromOrder,
    setTableId,
    setOrderType,
    orderType,
  ]);

  const sessionPatchRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  useEffect(() => {
    if (!cafeId || !activeOrderId) return;
    if (sessionPatchRef.current) clearTimeout(sessionPatchRef.current);
    sessionPatchRef.current = setTimeout(() => {
      apiPatch(`/api/cafes/${cafeId}/orders/${activeOrderId}/session`, {
        guestName: guestName.trim() || null,
        guestPhone: iranMobileForApi(guestPhone) ?? null,
        customerId: customerId ?? null,
      }).catch(() => undefined);
    }, 600);
    return () => {
      if (sessionPatchRef.current) clearTimeout(sessionPatchRef.current);
    };
  }, [guestName, guestPhone, customerId, activeOrderId, cafeId]);

  const handleTableSelect = useCallback(
    (table: TableBoardItem, activeOrder: Order | null) => {
      setShowTablePicker(false);

      if (activeOrder) {
        setTableId(table.id);
        hydrateFromOrder(activeOrder, menuById);
        syncUrl(table.id, activeOrder.id);
        setOrderMessage(t("sessionActive"));
        return;
      }

      const hadOpenSession = !!useCartStore.getState().activeOrderId;
      if (hadOpenSession) {
        clearSession();
      } else {
        setActiveOrderId(null);
      }

      setTableId(table.id);
      syncUrl(table.id, null);
      setOrderMessage(null);
    },
    [
      setTableId,
      hydrateFromOrder,
      menuById,
      syncUrl,
      setActiveOrderId,
      clearSession,
      t,
    ]
  );

  // Handle order type selection from the picker
  const handleOrderTypeSelect = useCallback(
    (type: OrderType) => {
      setOrderType(type);
      if (type === "table") {
        setShowTablePicker(true);
      }
    },
    [setOrderType]
  );

  // Go back to type picker (with clear)
  const handleBackToTypePicker = useCallback(() => {
    clearSession();
    syncUrl(null, null);
    setOrderMessage(null);
    setCouponMessage(null);
  }, [clearSession, syncUrl]);

  const tablesQuery = orderBranchId
    ? `?branchId=${encodeURIComponent(orderBranchId)}`
    : "";

  const { data: tables } = useQuery({
    queryKey: ["tables", cafeId, orderBranchId],
    queryFn: () => apiGet<Table[]>(`/api/cafes/${cafeId}/tables${tablesQuery}`),
    enabled: !!cafeId,
  });

  const { data: boardTables = [] } = useQuery({
    queryKey: ["tables-board", cafeId, orderBranchId, "transfer"],
    queryFn: () =>
      apiGet<TableBoardItem[]>(
        `/api/cafes/${cafeId}/tables/board${tablesQuery}`
      ),
    enabled: !!cafeId && showTransferPicker,
  });

  const voidItemMutation = useMutation({
    mutationFn: async (orderItemId: string) => {
      if (!cafeId || !activeOrderId) throw new Error("no session");
      return apiPatch<Order>(
        `/api/cafes/${cafeId}/orders/${activeOrderId}/items/${orderItemId}/void`,
        {}
      );
    },
    onSuccess: async (order) => {
      hydrateFromOrder(order, menuById);
      queryClient.invalidateQueries({ queryKey: ["tables-board", cafeId] });
      queryClient.invalidateQueries({ queryKey: ["orders-open", cafeId] });
    },
    onError: () => setOrderMessage(t("voidError")),
  });

  const transferTableMutation = useMutation({
    mutationFn: async (targetTableId: string) => {
      if (!cafeId || !activeOrderId) throw new Error("no session");
      return apiPost<Order>(`/api/cafes/${cafeId}/orders/${activeOrderId}/transfer`, {
        targetTableId,
      });
    },
    onSuccess: async (order) => {
      setShowTransferPicker(false);
      hydrateFromOrder(order, menuById);
      if (order.tableId) setTableId(order.tableId);
      syncUrl(order.tableId ?? null, order.id);
      setOrderMessage(t("transferSuccess"));
      queryClient.invalidateQueries({ queryKey: ["tables-board", cafeId] });
      queryClient.invalidateQueries({ queryKey: ["orders-open", cafeId] });
    },
    onError: (err: Error) => {
      const code = err instanceof ApiClientError ? err.code : "";
      if (code === "TABLE_OCCUPIED") setOrderMessage(t("tableOccupied"));
      else if (code === "TABLE_CLEANING") setOrderMessage(t("tableNotAvailable"));
      else setOrderMessage(t("transferError"));
    },
  });

  const handleVoidItem = async (orderItemId: string) => {
    const ok = await confirmDialog({
      description: t("confirmVoid"),
      variant: "destructive",
      confirmLabel: tCommon("confirm"),
    });
    if (!ok) return;
    voidItemMutation.mutate(orderItemId);
  };

  const freeTransferTables = boardTables.filter(
    (tbl) => tbl.status === "Free" && tbl.id !== tableId
  );

  const itemSearchQuery = itemSearch.trim();
  const isSearchingItems = itemSearchQuery.length > 0;

  const catalogForSearch = useMemo(
    () => allMenuItems ?? menuItems ?? [],
    [allMenuItems, menuItems]
  );

  const filteredItems = useMemo(() => {
    const base = isSearchingItems ? catalogForSearch : (menuItems ?? []);
    return base.filter((i) => {
      if (!i.isAvailable) return false;
      if (!isSearchingItems) return true;
      return menuItemMatchesSearch(i, itemSearchQuery, locale);
    });
  }, [catalogForSearch, menuItems, isSearchingItems, itemSearchQuery, locale]);

  const showItemsLoading = isSearchingItems ? loadingAllCatalog : loadingItems;

  const categoryNameById = useMemo(
    () => buildCategoryNameMap(categories ?? []),
    [categories]
  );

  const itemVisualKind = (item: MenuItem) =>
    inferMenuItemKind(item.categoryId, categoryNameById.get(item.categoryId));

  const sub = subtotal();
  const discount = appliedCoupon?.discountAmount ?? 0;
  const taxable = Math.max(0, sub - discount);
  const tax = Math.round(taxable * TAX_RATE);
  const total = taxable + tax;

  const couponErrorKey = (code: string) => {
    const map: Record<string, string> = {
      COUPON_NOT_FOUND: "couponInvalid",
      COUPON_INACTIVE: "couponInvalid",
      COUPON_EXPIRED: "couponExpired",
      COUPON_NOT_STARTED: "couponNotStarted",
      COUPON_LIMIT_REACHED: "couponLimitReached",
      COUPON_MIN_ORDER: "couponMinOrder",
      CART_EMPTY: "couponCartEmpty",
      COUPON_REQUIRED: "couponRequired",
      COUPON_NO_DISCOUNT: "couponInvalid",
    };
    return map[code] ?? "couponInvalid";
  };

  const validateCoupon = useMutation({
    mutationFn: async () => {
      if (!cafeId) throw new Error("no cafe");
      return apiPost<{
        couponId: string;
        code: string;
        discountAmount: number;
      }>(`/api/cafes/${cafeId}/coupons/validate`, {
        code: couponCode.trim(),
        subtotal: subtotal(),
      });
    },
    onSuccess: (data) => {
      setAppliedCoupon({
        id: data.couponId,
        code: data.code,
        discountAmount: data.discountAmount,
      });
      setCouponMessage({
        type: "success",
        text: t("couponApplied", {
          code: data.code,
          amount: formatCurrency(data.discountAmount, numberLocale),
        }),
      });
    },
    onError: (err: Error) => {
      setAppliedCoupon(null);
      const code = err instanceof ApiClientError ? err.code : "COUPON_NOT_FOUND";
      setCouponMessage({ type: "error", text: t(couponErrorKey(code)) });
    },
  });

  const openKitchenSlip = useCallback(() => {
    const pending = getPendingLines();
    const lines =
      pending.length > 0
        ? buildKitchenLines(pending, items)
        : cartToKitchenLines(items);
    if (lines.length === 0) return;
    setKitchenSlip({
      lines,
      orderId: activeOrderId ?? undefined,
      tableNumber: tables?.find((tbl) => tbl.id === tableId)?.number ?? null,
      guestName: guestName.trim() || null,
    });
  }, [getPendingLines, items, activeOrderId, tables, tableId, guestName]);

  const submitOrder = useMutation({
    mutationFn: async () => {
      if (!cafeId || items.length === 0) throw new Error("empty");
      const cart = useCartStore.getState();
      const pending = cart.getPendingLines();
      if (pending.length === 0) throw new Error("nothing pending");
      const kitchenLines = buildKitchenLines(pending, cart.items);
      const order = await submitOrderToApi({
        cafeId,
        orderBranchId: orderBranchId ?? undefined,
        cart,
        reservationId,
        cartItems: cart.items,
      });
      return { order, kitchenLines };
    },
    onMutate: () => ({ hadSession: !!useCartStore.getState().activeOrderId }),
    onSuccess: ({ order, kitchenLines }, _, context) => {
      hydrateFromOrder(order, menuById);
      syncUrl(order.tableId ?? tableId, order.id);
      setCouponMessage(null);
      if (kitchenLines.length > 0) {
        setKitchenSlip({
          lines: kitchenLines,
          orderId: order.id,
          tableNumber: order.tableNumber ?? null,
          guestName: order.guestName ?? (guestName.trim() || null),
        });
      }
      const baseMsg = context?.hadSession ? t("addToOrder") : t("orderPlaced");
      setOrderMessage(baseMsg);
      void apiPost<QueueTicket>(`/api/cafes/${cafeId}/queue/next`, {
        branchId: orderBranchId,
        customerLabel:
          order.guestName ?? (guestName.trim() || undefined),
        orderId: order.id,
      })
        .then((ticket) => {
          setOrderMessage(
            `${baseMsg} · ${t("queueNumber", { number: ticket.number })}`
          );
          queryClient.invalidateQueries({ queryKey: ["queue-today"] });
        })
        .catch(() => undefined);
      queryClient.invalidateQueries({ queryKey: ["orders-live", cafeId] });
      queryClient.invalidateQueries({ queryKey: ["orders-open", cafeId] });
      queryClient.invalidateQueries({ queryKey: ["tables-board", cafeId] });
      if (reservationId) {
        queryClient.invalidateQueries({ queryKey: ["reservations", cafeId] });
      }
    },
    onError: (err: Error) => {
      if (err instanceof ApiClientError) {
        if (err.code === "ORDER_NOT_FOUND" || err.code === "ORDER_NOT_OPEN") {
          setActiveOrderId(null);
          syncUrl(tableId, null);
        }
        const key =
          err.code === "TABLE_NOT_AVAILABLE"
            ? "tableNotAvailable"
            : err.code === "TABLE_OCCUPIED"
              ? "tableOccupied"
              : err.code === "PLAN_LIMIT_REACHED"
                ? "planLimit"
                : err.code === "INVALID_ORDER"
                  ? "orderInvalid"
                  : err.code === "ORDER_NOT_OPEN"
                    ? "orderNotOpen"
                    : err.code === "ORDER_NOT_FOUND"
                      ? "orderNotOpen"
                      : err.code === "VALIDATION_ERROR"
                        ? "orderValidation"
                        : "orderError";
        setOrderMessage(
          err.code === "VALIDATION_ERROR"
            ? err.message
            : key === "planLimit"
              ? tErrors("planLimit")
              : t(key)
        );
        return;
      }
      if (err.message === "nothing pending") {
        setOrderMessage(t("nothingPending"));
        return;
      }
      setOrderMessage(t("orderError"));
    },
  });

  const submitOrderAndPay = useMutation({
    mutationFn: async () => {
      if (!cafeId || items.length === 0) throw new Error("empty");
      const cart = useCartStore.getState();
      const pending = cart.getPendingLines();
      if (pending.length === 0) throw new Error("nothing pending");
      const kitchenLines = buildKitchenLines(pending, cart.items);
      const order = await submitOrderToApi({
        cafeId,
        orderBranchId: orderBranchId ?? undefined,
        cart,
        reservationId,
        cartItems: cart.items,
      });
      const due = orderAmountDue(order);
      if (isLocalOrder(order.id)) return { order, kitchenLines };
      const payBranchId = order.branchId ?? orderBranchId;
      if (due > 0) {
        if (!payBranchId) throw new Error("no branch");
        await requestPosPayment(cafeId, payBranchId, order.id, due);
        await apiPost(`/api/cafes/${cafeId}/orders/${order.id}/payments`, {
          payments: [{ method: "Card", amount: due }],
        });
      }
      return { order, kitchenLines };
    },
    onMutate: () => ({ hadSession: !!useCartStore.getState().activeOrderId }),
    onSuccess: ({ order, kitchenLines }, _, context) => {
      hydrateFromOrder(order, menuById);
      syncUrl(order.tableId ?? tableId, order.id);
      setCouponMessage(null);
      if (kitchenLines.length > 0) {
        setKitchenSlip({
          lines: kitchenLines,
          orderId: order.id,
          tableNumber: order.tableNumber ?? null,
          guestName: order.guestName ?? (guestName.trim() || null),
        });
      }
      const baseMsg = context?.hadSession ? t("orderPaidAdd") : t("orderPaidNew");
      setOrderMessage(baseMsg);
      queryClient.invalidateQueries({ queryKey: ["orders-live", cafeId] });
      queryClient.invalidateQueries({ queryKey: ["orders-open", cafeId] });
      queryClient.invalidateQueries({ queryKey: ["tables-board", cafeId] });
      if (reservationId) {
        queryClient.invalidateQueries({ queryKey: ["reservations", cafeId] });
      }
    },
    onError: (err: Error) => {
      if (err instanceof ApiClientError) {
        if (
          err.code === "POS_DEVICE_CONNECTION_FAILED" ||
          err.code === "POS_DEVICE_TIMEOUT" ||
          err.code === "POS_DEVICE_REJECTED" ||
          err.code.startsWith("POS_DEVICE")
        ) {
          setOrderMessage(posDeviceErrorMessage(err, t));
          return;
        }
        if (err.code === "ORDER_NOT_FOUND" || err.code === "ORDER_NOT_OPEN") {
          setActiveOrderId(null);
          syncUrl(tableId, null);
        }
        const key =
          err.code === "TABLE_NOT_AVAILABLE"
            ? "tableNotAvailable"
            : err.code === "TABLE_OCCUPIED"
              ? "tableOccupied"
              : err.code === "PLAN_LIMIT_REACHED"
                ? "planLimit"
                : err.code === "INVALID_ORDER"
                  ? "orderInvalid"
                  : err.code === "ORDER_NOT_OPEN"
                    ? "orderNotOpen"
                    : err.code === "ORDER_NOT_FOUND"
                      ? "orderNotOpen"
                      : err.code === "VALIDATION_ERROR"
                        ? "orderValidation"
                        : "orderError";
        setOrderMessage(
          err.code === "VALIDATION_ERROR"
            ? err.message
            : key === "planLimit"
              ? tErrors("planLimit")
              : t(key)
        );
        return;
      }
      if (err.message === "nothing pending") {
        setOrderMessage(t("nothingPending"));
        return;
      }
      if (err.message === "no branch") {
        setOrderMessage(t("posDeviceNoBranch"));
        return;
      }
      setOrderMessage(t("payError"));
    },
  });

  const pendingCount = getPendingLines().length;
  const isOrderBusy = submitOrder.isPending || submitOrderAndPay.isPending;

  // Counter/takeaway orders don't require a table
  const canSubmitOrder =
    pendingCount > 0 &&
    (orderType === "counter" ||
      orderType === "takeaway" ||
      !!tableId ||
      !!customerId ||
      guestName.trim().length > 0);

  // Show order type picker when there's no active session
  const showTypePicker =
    posMode === "order" &&
    orderType === null &&
    items.length === 0 &&
    !urlOrderId &&
    !activeOrderId;

  // The current table number for display
  const currentTableNumber = tables?.find((tbl) => tbl.id === tableId)?.number;

  if (!cafeId) return null;

  return (
    <div
      className="flex h-full min-h-0 w-full flex-col overflow-hidden"
      dir={isRtl ? "rtl" : "ltr"}
    >
      {/* ── Top bar: mode switcher ─────────────────────────────────────────── */}
      <div className="flex shrink-0 items-center gap-2 border-b border-border px-1 pb-2">
        <Button
          size="sm"
          variant={posMode === "order" ? "default" : "outline"}
          onClick={() => setPosMode("order")}
        >
          {t("modeOrder")}
        </Button>
        <Button
          size="sm"
          variant={posMode === "pay" ? "default" : "outline"}
          onClick={() => setPosMode("pay")}
        >
          {t("modePay")}
        </Button>

        <div className="flex-1" />
      </div>

      {/* ── Pay mode ──────────────────────────────────────────────────────── */}
      {posMode === "pay" ? (
        <PosPayPanel
          cafeId={cafeId}
          numberLocale={numberLocale}
          branchId={orderBranchId}
        />
      ) : showTypePicker ? (
        /* ── Order type picker ──────────────────────────────────────────── */
        <OrderTypePicker onSelect={handleOrderTypeSelect} t={t} />
      ) : (
        /* ── Order screen ───────────────────────────────────────────────── */
        <div className="flex min-h-0 flex-1 flex-col gap-2 overflow-hidden pt-2">
          {/* Order screen header */}
          <div className="flex shrink-0 items-center gap-2 px-1">
            {/* Back / new order button */}
            <button
              type="button"
              onClick={handleBackToTypePicker}
              aria-label={t("newOrder")}
              className="flex shrink-0 cursor-pointer items-center gap-1 rounded-lg px-2 py-1.5 text-xs text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
            >
              {isRtl ? (
                <ChevronRight className="size-4" />
              ) : (
                <ChevronLeft className="size-4" />
              )}
              {t("newOrder")}
            </button>

            {/* Order type badge — tappable to change table */}
            {orderType ? (
              <OrderTypeBadge
                orderType={orderType}
                tableNumber={currentTableNumber}
                onClick={
                  orderType === "table"
                    ? () => setShowTablePicker(true)
                    : undefined
                }
                t={t}
              />
            ) : null}

            {/* Active order number */}
            {activeOrderId ? (
              <span className="text-xs text-muted-foreground">
                #
                {activeOrderDisplayNumber
                  ? String(activeOrderDisplayNumber)
                  : formatOrderNumber({ id: activeOrderId })}
              </span>
            ) : null}

            <div className="flex-1" />

            {/* Queue bar */}
            {cafeId ? (
              <PosQueueBar cafeId={cafeId} branchId={orderBranchId} />
            ) : null}
          </div>

          {/* Reservation banner */}
          {reservationId && reservationGuest ? (
            <div className="mx-1 shrink-0 rounded-lg border border-primary/30 bg-primary/5 px-3 py-2 text-sm text-primary">
              {t("reservationBanner", { name: reservationGuest })}
            </div>
          ) : null}

          {/* ── Main split: menu + cart ──────────────────────────────────── */}
          <div className="flex min-h-0 flex-1 gap-3 overflow-hidden">
            {/* ── Menu panel ────────────────────────────────────────────── */}
            <div className="flex min-h-0 min-w-0 flex-1 flex-col gap-2 overflow-hidden">
              {/* Search bar */}
              <div className="relative shrink-0">
                <Search
                  className="pointer-events-none absolute start-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground"
                  aria-hidden
                />
                <Input
                  type="search"
                  value={itemSearch}
                  onChange={(e) => setItemSearch(e.target.value)}
                  placeholder={t("searchItemsPlaceholder")}
                  aria-label={t("searchItems")}
                  className="h-10 ps-9 pe-9"
                />
                {itemSearch ? (
                  <Button
                    type="button"
                    variant="ghost"
                    size="icon"
                    className="absolute end-1 top-1/2 size-7 -translate-y-1/2"
                    onClick={() => setItemSearch("")}
                    aria-label={tCommon("cancel")}
                  >
                    <X className="size-4" />
                  </Button>
                ) : null}
              </div>

              {/* Horizontal scrolling category tabs — no wrap */}
              <div className="flex shrink-0 gap-1.5 overflow-x-auto pb-0.5 [scrollbar-width:none] [-ms-overflow-style:none]">
                <Button
                  size="sm"
                  variant={selectedCategory === "all" ? "default" : "outline"}
                  className="shrink-0"
                  onClick={() => setSelectedCategory("all")}
                >
                  {t("allCategories")}
                </Button>
                {loadingCategories
                  ? Array.from({ length: 4 }).map((_, i) => (
                      <Skeleton key={i} className="h-9 w-20 shrink-0" />
                    ))
                  : categories?.map((c) => (
                      <Button
                        key={c.id}
                        size="sm"
                        variant={
                          selectedCategory === c.id ? "default" : "outline"
                        }
                        className="shrink-0 gap-1.5"
                        onClick={() => setSelectedCategory(c.id)}
                      >
                        <CategoryVisual
                          icon={c.icon}
                          iconPresetId={c.iconPresetId}
                          iconStyle={c.iconStyle}
                          imageUrl={c.imageUrl}
                          size="xs"
                        />
                        {getMenuPrimaryName(c, locale)}
                      </Button>
                    ))}
              </div>

              {/* Product grid — bigger cards with image area */}
              <div className="min-h-0 flex-1 overflow-y-auto overscroll-contain">
                <div className="grid grid-cols-2 gap-2 content-start sm:grid-cols-3 lg:grid-cols-4">
                  {showItemsLoading
                    ? Array.from({ length: 8 }).map((_, i) => (
                        <Skeleton key={i} className="h-36 rounded-xl" />
                      ))
                    : filteredItems.length === 0 && isSearchingItems
                      ? (
                          <p className="col-span-full py-10 text-center text-sm text-muted-foreground">
                            {t("searchNoResults")}
                          </p>
                        )
                      : filteredItems.map((item) => {
                          const qty = items.find(
                            (ci) => ci.menuItem.id === item.id
                          )?.quantity;
                          return (
                            <button
                              key={item.id}
                              type="button"
                              onClick={() => addItem(item)}
                              className={cn(
                                "group relative flex cursor-pointer flex-col gap-2 rounded-xl border bg-card p-2.5 text-start shadow-sm transition-all hover:border-primary hover:shadow-md active:scale-[0.97]",
                                qty
                                  ? "border-primary"
                                  : "border-border"
                              )}
                            >
                              {/* Thumbnail */}
                              <div className="relative w-full overflow-hidden rounded-lg border border-border/50 bg-muted aspect-[4/3]">
                                <MenuItemMedia
                                  imageUrl={item.imageUrl}
                                  kind={itemVisualKind(item)}
                                  size="sm"
                                />
                                {item.videoUrl ? (
                                  <span
                                    className="absolute bottom-0 end-0 rounded-ss-sm bg-black/55 p-px"
                                    aria-hidden
                                  >
                                    <Video className="h-2.5 w-2.5 text-white" />
                                  </span>
                                ) : null}
                                {/* Cart quantity badge */}
                                {qty ? (
                                  <span className="absolute start-1.5 top-1.5 flex h-5 min-w-5 items-center justify-center rounded-full bg-primary px-1 text-[10px] font-bold text-primary-foreground">
                                    {qty}
                                  </span>
                                ) : null}
                              </div>

                              {/* Info */}
                              <div className="min-w-0">
                                <MenuItemLabels
                                  item={item}
                                  lines={2}
                                  primaryClassName="text-sm font-medium leading-snug"
                                  secondaryClassName="text-[10px]"
                                />
                                <p className="mt-1 text-sm font-semibold text-primary">
                                  {formatCurrency(item.price, numberLocale)}
                                </p>
                              </div>
                            </button>
                          );
                        })}
                </div>
              </div>
            </div>

            {/* ── Cart sidebar ──────────────────────────────────────────── */}
            <Card className="flex h-full min-h-0 w-[min(100%,21rem)] shrink-0 flex-col overflow-hidden sm:w-72 lg:w-80">
              <CardHeader className="shrink-0 space-y-2 p-3 pb-2">
                {/* Cart header: title + table/type badge */}
                <div className="flex items-center justify-between gap-2">
                  <div className="flex items-center gap-2">
                    <ShoppingCart className="size-4 text-muted-foreground" />
                    <CardTitle className="text-sm">{t("takeOrder")}</CardTitle>
                  </div>

                  {orderType === "table" ? (
                    tableId ? (
                      <button
                        type="button"
                        onClick={() => setShowTablePicker(true)}
                        className="shrink-0 cursor-pointer rounded-md border-2 border-primary bg-primary/10 px-2 py-0.5 text-xs font-semibold text-primary transition-colors hover:bg-primary/20"
                      >
                        {t("table")}{" "}
                        {currentTableNumber ?? "—"}
                      </button>
                    ) : (
                      <button
                        type="button"
                        onClick={() => setShowTablePicker(true)}
                        className="shrink-0 cursor-pointer rounded-md border border-dashed border-primary px-2 py-0.5 text-xs text-primary transition-colors hover:bg-primary/5"
                      >
                        {t("selectTableBoard")}
                      </button>
                    )
                  ) : orderType ? (
                    <span
                      className={cn(
                        "shrink-0 rounded-full px-2.5 py-0.5 text-xs font-medium",
                        orderType === "counter"
                          ? "bg-blue-50 text-blue-700"
                          : "bg-amber-50 text-amber-700"
                      )}
                    >
                      {orderType === "counter"
                        ? t("counterBadge")
                        : t("takeawayBadge")}
                    </span>
                  ) : null}
                </div>

                {/* Customer picker */}
                {cafeId ? (
                  <PosCustomerPicker
                    compact
                    cafeId={cafeId}
                    guestName={guestName}
                    guestPhone={guestPhone}
                    customerId={customerId}
                    onGuestNameChange={setGuestName}
                    onGuestPhoneChange={setGuestPhone}
                    onCustomerChange={setCustomer}
                    onClearCustomer={clearCustomer}
                  />
                ) : null}

                {/* Transfer table (for table orders with active session) */}
                {activeOrderId && tableId ? (
                  <Button
                    type="button"
                    variant="outline"
                    size="sm"
                    className="h-8 w-full text-xs"
                    onClick={() => setShowTransferPicker(true)}
                  >
                    {t("transferTable")}
                  </Button>
                ) : null}

                {/* Assign table button (for counter orders) */}
                {orderType === "counter" && activeOrderId ? (
                  <Button
                    type="button"
                    variant="outline"
                    size="sm"
                    className="h-8 w-full text-xs"
                    onClick={() => setShowTablePicker(true)}
                  >
                    {t("assignTable")} →
                  </Button>
                ) : null}
              </CardHeader>

              <CardContent className="flex min-h-0 flex-1 flex-col overflow-hidden p-3 pt-0">
                {/* Cart items */}
                <div className="min-h-0 flex-1 space-y-1.5 overflow-y-auto overscroll-contain pe-0.5">
                  {items.length === 0 ? (
                    <p className="py-4 text-center text-sm text-muted-foreground">
                      {t("emptyCart")}
                    </p>
                  ) : (
                    items.map((line) => (
                      <div
                        key={line.orderItemId ?? line.menuItem.id}
                        className={cn(
                          "flex items-center gap-2 rounded-lg border border-border p-2",
                          line.isVoided && "opacity-60"
                        )}
                      >
                        <div className="min-w-0 flex-1">
                          <MenuItemLabels
                            item={line.menuItem}
                            lines={1}
                            primaryClassName={cn(
                              "text-xs font-medium",
                              line.isVoided &&
                                "line-through text-muted-foreground"
                            )}
                            secondaryClassName="text-[10px]"
                          />
                          <p className="mt-0.5 text-[11px] text-muted-foreground">
                            {line.isVoided ? (
                              <span>{t("voided")}</span>
                            ) : (
                              formatCurrency(
                                line.menuItem.price * line.quantity,
                                numberLocale
                              )
                            )}
                          </p>
                        </div>

                        <div
                          className="flex shrink-0 items-center gap-0.5"
                          onClick={(e) => e.stopPropagation()}
                          onKeyDown={(e) => e.stopPropagation()}
                        >
                          {isManager &&
                          line.orderItemId &&
                          !line.isVoided &&
                          activeOrderId ? (
                            <button
                              type="button"
                              className="cursor-pointer text-[10px] text-destructive hover:underline"
                              onClick={() => handleVoidItem(line.orderItemId!)}
                              aria-label={t("voidItem")}
                            >
                              {t("void")}
                            </button>
                          ) : null}
                          {!line.isVoided ? (
                            <>
                              <Button
                                size="icon"
                                variant="outline"
                                className="h-8 w-8"
                                onClick={() =>
                                  updateQty(line.menuItem.id, line.quantity - 1)
                                }
                              >
                                <Minus className="h-3.5 w-3.5" />
                              </Button>
                              <span className="w-6 text-center text-xs font-medium">
                                {formatNumber(line.quantity, numberLocale)}
                              </span>
                              <Button
                                size="icon"
                                variant="outline"
                                className="h-8 w-8"
                                onClick={() =>
                                  updateQty(line.menuItem.id, line.quantity + 1)
                                }
                              >
                                <Plus className="h-3.5 w-3.5" />
                              </Button>
                              <Button
                                size="icon"
                                variant="ghost"
                                className="h-8 w-8 text-destructive"
                                onClick={() => removeItem(line.menuItem.id)}
                              >
                                <Trash2 className="h-3.5 w-3.5" />
                              </Button>
                            </>
                          ) : null}
                        </div>
                      </div>
                    ))
                  )}
                </div>

                {/* Totals + actions */}
                <div className="shrink-0 space-y-1.5 border-t border-border bg-card pt-2">
                  {/* Coupon row */}
                  <div className="flex flex-wrap items-end gap-1.5">
                    <LabeledField
                      label={t("couponCode")}
                      htmlFor="pos-coupon"
                      className="min-w-0 flex-1"
                    >
                      <Input
                        id="pos-coupon"
                        value={couponCode}
                        onChange={(e) => {
                          setCouponCode(e.target.value);
                          if (couponMessage) setCouponMessage(null);
                        }}
                        onKeyDown={(e) => {
                          if (
                            e.key === "Enter" &&
                            !appliedCoupon &&
                            couponCode.trim() &&
                            !validateCoupon.isPending
                          ) {
                            e.preventDefault();
                            validateCoupon.mutate();
                          }
                        }}
                        disabled={!!appliedCoupon}
                        dir="ltr"
                        className="h-8 text-end text-sm"
                      />
                    </LabeledField>
                    {appliedCoupon ? (
                      <Button
                        variant="outline"
                        onClick={() => {
                          clearCoupon();
                          setCouponMessage({
                            type: "success",
                            text: t("couponRemoved"),
                          });
                        }}
                      >
                        {t("removeCoupon")}
                      </Button>
                    ) : (
                      <Button
                        variant="outline"
                        disabled={
                          !couponCode.trim() ||
                          items.length === 0 ||
                          validateCoupon.isPending
                        }
                        onClick={() => validateCoupon.mutate()}
                      >
                        {t("applyCoupon")}
                      </Button>
                    )}
                  </div>

                  {couponMessage ? (
                    <p
                      className={cn(
                        "text-center text-sm",
                        couponMessage.type === "success"
                          ? "text-[#0F6E56]"
                          : "text-[#A32D2D]"
                      )}
                    >
                      {couponMessage.text}
                    </p>
                  ) : null}

                  {appliedCoupon ? (
                    <div className="flex justify-between text-sm text-[#BA7517]">
                      <span>{t("couponActive", { code: appliedCoupon.code })}</span>
                      <span>-{formatCurrency(discount, numberLocale)}</span>
                    </div>
                  ) : null}

                  <div className="flex justify-between text-sm">
                    <span>{t("subtotal")}</span>
                    <span>{formatCurrency(sub, numberLocale)}</span>
                  </div>
                  {discount > 0 ? (
                    <div className="flex justify-between text-sm text-[#0F6E56]">
                      <span>{t("discount")}</span>
                      <span>-{formatCurrency(discount, numberLocale)}</span>
                    </div>
                  ) : null}
                  <div className="flex justify-between text-sm">
                    <span>{t("tax")}</span>
                    <span>{formatCurrency(tax, numberLocale)}</span>
                  </div>
                  <div className="flex justify-between text-sm font-bold">
                    <span>{t("total")}</span>
                    <span>{formatCurrency(total, numberLocale)}</span>
                  </div>

                  {!isOnline ? (
                    <p className="rounded-md border border-amber-200 bg-amber-50 px-2 py-1 text-center text-[11px] text-amber-700">
                      {t("offlineQueueNotice")}
                    </p>
                  ) : null}

                  {orderMessage ? (
                    <p className="text-center text-xs text-primary">
                      {orderMessage}
                    </p>
                  ) : null}

                  {!canSubmitOrder &&
                  items.length > 0 &&
                  orderType !== "counter" &&
                  orderType !== "takeaway" ? (
                    <p className="text-center text-[10px] text-amber-700">
                      {t("needTableOrName")}
                    </p>
                  ) : null}

                  {items.some((line) => !line.isVoided) ? (
                    <Button
                      type="button"
                      size="sm"
                      variant="outline"
                      className="w-full"
                      onClick={openKitchenSlip}
                    >
                      {t("kitchenSlip")}
                    </Button>
                  ) : null}

                  <div className="flex flex-col gap-2 pt-0.5">
                    <Button
                      size="sm"
                      className="w-full"
                      disabled={!canSubmitOrder || isOrderBusy}
                      onClick={() => submitOrderAndPay.mutate()}
                    >
                      {submitOrderAndPay.isPending
                        ? "..."
                        : t("submitOrderAndPay")}
                    </Button>
                    <div className="flex gap-2">
                      <Button
                        size="sm"
                        variant="outline"
                        className="flex-1"
                        disabled={!canSubmitOrder || isOrderBusy}
                        onClick={() => submitOrder.mutate()}
                      >
                        {submitOrder.isPending ? "..." : t("submitOrder")}
                      </Button>
                      <Button
                        size="sm"
                        variant="outline"
                        onClick={handleBackToTypePicker}
                      >
                        {t("clearCart")}
                      </Button>
                    </div>
                  </div>
                </div>
              </CardContent>
            </Card>
          </div>
        </div>
      )}

      {/* ── Table picker modal (for Table orders & counter assign) ────────── */}
      {showTablePicker ? (
        <div className="fixed inset-0 z-50 flex items-start justify-center overflow-y-auto bg-black/50 p-4 pt-16">
          <div className="w-full max-w-3xl rounded-2xl border border-border bg-background p-5 shadow-2xl">
            <div className="mb-4 flex items-center justify-between gap-2">
              <h3 className="text-base font-semibold">{t("selectTableBoard")}</h3>
              <Button
                type="button"
                variant="ghost"
                size="icon"
                onClick={() => {
                  setShowTablePicker(false);
                  // If table type was selected but user dismissed without choosing a table,
                  // go back to type picker
                  if (orderType === "table" && !tableId) {
                    setOrderType(null);
                  }
                }}
              >
                <X className="size-5" />
              </Button>
            </div>
            {cafeId ? (
              <PosTableBoard
                cafeId={cafeId}
                numberLocale={numberLocale}
                selectedTableId={tableId}
                branchId={orderBranchId}
                onSelectTable={handleTableSelect}
              />
            ) : null}
          </div>
        </div>
      ) : null}

      {/* ── Kitchen slip modal ────────────────────────────────────────────── */}
      {kitchenSlip ? (
        <PosSlipModal
          variant="kitchen"
          cafeName={cafeName}
          kitchenLines={kitchenSlip.lines}
          orderId={kitchenSlip.orderId}
          tableNumber={kitchenSlip.tableNumber}
          guestName={kitchenSlip.guestName}
          onClose={() => setKitchenSlip(null)}
        />
      ) : null}

      {/* ── Transfer table modal ──────────────────────────────────────────── */}
      {showTransferPicker ? (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4">
          <div className="w-full max-w-sm rounded-xl border border-border bg-background p-4 shadow-lg">
            <p className="mb-3 text-sm font-medium">{t("selectTargetTable")}</p>
            <div className="mb-4 flex max-h-48 flex-wrap gap-2 overflow-y-auto">
              {freeTransferTables.length === 0 ? (
                <p className="text-sm text-muted-foreground">
                  {t("noOrderOnTable")}
                </p>
              ) : (
                freeTransferTables.map((tbl) => (
                  <Button
                    key={tbl.id}
                    type="button"
                    variant="outline"
                    size="sm"
                    disabled={transferTableMutation.isPending}
                    onClick={() => transferTableMutation.mutate(tbl.id)}
                  >
                    {t("table")} {tbl.number}
                  </Button>
                ))
              )}
            </div>
            <Button
              type="button"
              variant="ghost"
              className="w-full"
              onClick={() => setShowTransferPicker(false)}
            >
              {tCommon("cancel")}
            </Button>
          </div>
        </div>
      ) : null}
    </div>
  );
}
