"use client";

import { useRouter } from "next/navigation";
import { usePopCompanyPath } from "@/hooks/usePopCompanyPath";
import React, {
	useCallback,
	useEffect,
	useMemo,
	useRef,
	useState,
} from "react";
import { apiClient } from "@/lib/api/client";
import { type CartItemWithId, useCartSync } from "../common/useCartSync";
import { NumberPadModal, type PackageEntry } from "../inbound/NumberPadModal";
import { LoadingUnitModal, type LoadingUnitSelection } from "../inbound/LoadingUnitModal";
import { SimpleKeypadModal } from "../common/SimpleKeypadModal";
import { COLOR_MAP } from "../common/theme";

/* ------------------------------------------------------------------ */
/* Types                                                               */
/* ------------------------------------------------------------------ */

interface Warehouse {
	warehouse_code: string;
	warehouse_name: string;
	warehouse_type?: string;
}

/** CartItemWithId -> 화면 표시용 파싱 결과 */
interface CartItemParsed {
	id: string;
	rowKey: string;
	dbId: string;
	source_table: string;
	source_id: string;
	reference_no: string;
	item_code: string;
	item_name: string;
	spec: string;
	material: string;
	order_qty: number;
	remain_qty: number;
	outbound_qty: number;
	unit_price: number;
	customer_code: string;
	customer_name: string;
	order_date?: string;
	packages?: PackageEntry[];
	image?: string | null;
	outbound_type: string;
	loading_code?: string;
	loading_name?: string;
}

/* ------------------------------------------------------------------ */
/* Helper: CartItemWithId -> CartItemParsed                            */
/* ------------------------------------------------------------------ */
function toCartItemParsed(item: CartItemWithId): CartItemParsed {
	const data = item.row;

	return {
		id: item.rowKey || String(data.id ?? ""),
		rowKey: item.rowKey,
		dbId: item.cartId || "",
		source_table:
			item.sourceTable || String(data.source_table ?? ""),
		source_id: item.rowKey || String(data.id ?? ""),
		reference_no: String(data.reference_no ?? ""),
		item_code: String(data.item_code ?? ""),
		item_name: String(data.item_name ?? ""),
		spec: String(data.spec ?? ""),
		material: String(data.material ?? ""),
		order_qty: Number(data.order_qty ?? 0),
		remain_qty: Number(data.remain_qty ?? 0),
		outbound_qty: item.quantity,
		unit_price: Number(data.unit_price ?? 0),
		customer_code: String(data.customer_code ?? ""),
		customer_name: String(data.customer_name ?? ""),
		order_date: data.order_date ? String(data.order_date) : undefined,
		// packageEntries의 실제 런타임 타입은 NumberPadModal의 PackageEntry[]
		packages: item.packageEntries as unknown as PackageEntry[] | undefined,
		image: data.image ? String(data.image) : null,
		outbound_type: String(data.outbound_type ?? ""),
		loading_code: data.loading_code ? String(data.loading_code) : undefined,
		loading_name: data.loading_name ? String(data.loading_name) : undefined,
	};
}

/* ------------------------------------------------------------------ */
/* Component                                                           */
/* ------------------------------------------------------------------ */

interface OutboundCartPageProps {
	backUrl: string;
}

export function OutboundCartPage({ backUrl }: OutboundCartPageProps) {
	const router = useRouter();
  const companyPath = usePopCompanyPath();

	/* Cart sync hook — 출고 카테고리 공통 */
	const cart = useCartSync("outbound");

	/* Derived: parsed items from cart */
	const items = useMemo(
		() => cart.cartItems.map(toCartItemParsed),
		[cart.cartItems],
	);

	/* Selection */
	const [selectedItems, setSelectedItems] = useState<Set<string>>(new Set());

	/* Auto-select all when items change */
	useEffect(() => {
		if (items.length > 0) {
			setSelectedItems(new Set(items.map((i) => i.id)));
		}
	}, [items]);

	/* Warehouse */
	const [warehouses, setWarehouses] = useState<Warehouse[]>([]);
	const [selectedWarehouse, setSelectedWarehouse] = useState<string>("");
	const [warehousePickerOpen, setWarehousePickerOpen] = useState(false);

	/* Outbound number */
	const [outboundNumber, setOutboundNumber] = useState<string>("");

	/* Confirm result modal */
	const [confirmResult, setConfirmResult] = useState<{
		outboundNumber: string;
		items: CartItemParsed[];
		warehouse: string;
		date: string;
	} | null>(null);

	/* Outbound date */
	const [outboundDate, setOutboundDate] = useState<string>(
		new Date().toISOString().slice(0, 10),
	);

	/* Confirm state */
	const [confirming, setConfirming] = useState(false);
	const [resultMsg, setResultMsg] = useState<string | null>(null);

	/* Simple keypad modal (for qty edit) */
	const [numpadOpen, setNumpadOpen] = useState(false);
	const [numpadTarget, setNumpadTarget] = useState<CartItemParsed | null>(null);

	/* Packaging modal (for package unit registration) */
	const [packagingOpen, setPackagingOpen] = useState(false);
	const [packagingTarget, setPackagingTarget] = useState<CartItemParsed | null>(null);

	/* 거래처 필터 */
	const [selectedCustomerFilter, setSelectedCustomerFilter] = useState<string>("");

	/* 거래처 목록 추출 (중복 제거) */
	const customerList = useMemo(() => {
		const map = new Map<string, string>();
		items.forEach((item) => {
			if (item.customer_code && !map.has(item.customer_code)) {
				map.set(item.customer_code, item.customer_name);
			}
		});
		return Array.from(map.entries()).map(([code, name]) => ({ code, name }));
	}, [items]);

	/* 거래처 1개면 자동 선택 */
	useEffect(() => {
		if (customerList.length === 1) {
			setSelectedCustomerFilter(customerList[0].code);
		}
	}, [customerList]);

	/* 렌더링용 filteredItems (선택/확정 로직은 전체 items 기반 유지) */
	const filteredItems = useMemo(() => {
		if (!selectedCustomerFilter) return items;
		return items.filter((item) => item.customer_code === selectedCustomerFilter);
	}, [items, selectedCustomerFilter]);

	/* ------------------------------------------------------------------ */
	/* Fetch warehouses                                                    */
	/* ------------------------------------------------------------------ */
	const fetchedRef = useRef(false);

	const fetchWarehouses = useCallback(async () => {
		try {
			const res = await apiClient.get("/outbound/warehouses");
			const data: Warehouse[] = res.data?.data ?? [];
			setWarehouses(data);
			if (data.length > 0) {
				setSelectedWarehouse(data[0].warehouse_code);
			}
		} catch {
			/* keep empty */
		}
	}, []);

	useEffect(() => {
		if (fetchedRef.current) return;
		fetchedRef.current = true;
		fetchWarehouses();
	}, [fetchWarehouses]);

	/* ------------------------------------------------------------------ */
	/* Selection                                                           */
	/* ------------------------------------------------------------------ */
	const toggleSelect = (id: string) => {
		setSelectedItems((prev) => {
			const next = new Set(prev);
			if (next.has(id)) next.delete(id);
			else next.add(id);
			return next;
		});
	};

	const toggleSelectAll = () => {
		if (selectedItems.size === items.length) {
			setSelectedItems(new Set());
		} else {
			setSelectedItems(new Set(items.map((i) => i.id)));
		}
	};

	/* ------------------------------------------------------------------ */
	/* Qty edit via numpad                                                  */
	/* ------------------------------------------------------------------ */
	const openNumpad = (item: CartItemParsed) => {
		setNumpadTarget(item);
		setNumpadOpen(true);
	};

	const handleNumpadConfirm = (qty: number) => {
		if (!numpadTarget) return;
		const finalQty = Math.min(qty, numpadTarget.remain_qty);

		cart.updateItemQuantity(numpadTarget.rowKey, finalQty);
		setNumpadTarget(null);
	};

	/* Packaging handlers */
	const openPackaging = (item: CartItemParsed) => {
		setPackagingTarget(item);
		setPackagingOpen(true);
	};

	const handlePackagingConfirm = (_qty: number, packages: PackageEntry[]) => {
		if (!packagingTarget) return;
		const finalQty = packagingTarget.outbound_qty;

		cart.updateItemQuantity(
			packagingTarget.rowKey,
			finalQty,
			undefined,
			// eslint-disable-next-line @typescript-eslint/no-explicit-any
			packages.length > 0 ? (packages as any) : undefined,
		);
		setPackagingTarget(null);
	};

	/* ------------------------------------------------------------------ */
	/* Remove item                                                         */
	/* ------------------------------------------------------------------ */
	const handleRemove = (rowKey: string) => {
		cart.removeItem(rowKey);
		setSelectedItems((prev) => {
			const next = new Set(prev);
			next.delete(rowKey);
			return next;
		});
		// Auto-save effect below will persist change to DB
	};

	/* Auto-save: persist dirty changes to DB after a short debounce */
	const autoSaveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
	useEffect(() => {
		if (!cart.isDirty || cart.syncStatus === "saving") return;
		if (autoSaveTimerRef.current) clearTimeout(autoSaveTimerRef.current);
		autoSaveTimerRef.current = setTimeout(() => {
			cart.saveToDb().catch(() => {});
		}, 500);
		return () => {
			if (autoSaveTimerRef.current) clearTimeout(autoSaveTimerRef.current);
		};
	}, [cart.isDirty, cart.syncStatus, cart]);

	/* ------------------------------------------------------------------ */
	/* Derived                                                             */
	/* ------------------------------------------------------------------ */
	const selectedItemsList = items.filter((i) => selectedItems.has(i.id));

	/* Loading unit modal — 선택된 품목 일괄 적재함 적용 */
	const [loadingModalOpen, setLoadingModalOpen] = useState(false);

	const openLoadingModal = () => {
		setLoadingModalOpen(true);
	};

	const selectedPkgCodes = useMemo(() => {
		return selectedItemsList
			.filter((item) => item.packages && item.packages.length > 0)
			.map((item) => item.packages![0].unit.value);
	}, [selectedItemsList]);

	const handleLoadingSelect = (lu: LoadingUnitSelection) => {
		for (const item of selectedItemsList) {
			cart.updateItemRow(item.rowKey, {
				loading_code: lu.loading_code,
				loading_name: lu.loading_name,
			});
		}
	};

	const handleLoadingClear = () => {
		for (const item of selectedItemsList) {
			cart.updateItemRow(item.rowKey, {
				loading_code: null,
				loading_name: null,
			});
		}
	};

	/* ------------------------------------------------------------------ */
	/* Confirm outbound                                                    */
	/* ------------------------------------------------------------------ */
	const handleConfirm = async () => {
		if (selectedItemsList.length === 0) return;

		if (!selectedWarehouse) {
			setResultMsg("오류: 출고 창고를 선택해주세요.");
			return;
		}

		setConfirming(true);
		setResultMsg(null);

		try {
			// 확정 시점에 채번 (동시접속 충돌 방지)
			// numbering_rules 테이블에서 채번규칙 직접 조회
			let finalNumber = "";
			try {
				const ruleRes: any = await apiClient
					.get("/numbering-rules/by-column/outbound_mng/outbound_number")
					.catch(() => null);
				const ruleId = ruleRes?.data?.data?.ruleId;
				const url =
					ruleId
						? `/outbound/generate-number?ruleId=${encodeURIComponent(ruleId)}`
						: "/outbound/generate-number";
				const numRes = await apiClient.get(url);
				if (numRes.data?.success && numRes.data?.data) {
					finalNumber = numRes.data.data;
					setOutboundNumber(finalNumber);
				}
			} catch {
				/* backend will handle */
			}

			// 헤더 outbound_type: 단일이면 그대로, 혼합이면 "혼합출고"
			const uniqueTypes = [...new Set(selectedItemsList.map((i) => i.outbound_type).filter(Boolean))];
			const headerOutboundType = uniqueTypes.length === 1 ? uniqueTypes[0] : (uniqueTypes.length > 1 ? "혼합출고" : "출고");

			const payload = {
				outbound_number: finalNumber,
				outbound_date: outboundDate,
				warehouse_code: selectedWarehouse,
				outbound_type: headerOutboundType,
				items: selectedItemsList.map((item, idx) => ({
					outbound_type: item.outbound_type || headerOutboundType,
					item_number: item.item_code,
					item_name: item.item_name,
					spec: item.spec || "",
					material: item.material || "",
					unit: "EA",
					outbound_qty: String(item.outbound_qty),
					unit_price: String(item.unit_price || 0),
					total_amount: String(
						(item.outbound_qty || 0) * (item.unit_price || 0),
					),
					reference_number: item.reference_no,
					customer_code: item.customer_code,
					customer_name: item.customer_name,
					outbound_status: "출고완료",
					source_table: item.source_table,
					source_id: item.source_id || item.id,
					seq_no: idx + 1,
				})),
			};

			const res = await apiClient.post("/outbound", payload);

			if (res.data?.success) {
				// Remove confirmed items from cart - direct DB delete for reliability
				const confirmedItems = [...selectedItemsList];
				const { dataApi } = await import("@/lib/api/data");
				const confirmPromises = confirmedItems
					.filter((item) => item.dbId)
					.map((item) =>
						dataApi
							.updateRecord("cart_items", item.dbId, { status: "confirmed" })
							.catch(() => {}),
					);
				await Promise.all(confirmPromises);

				// Also clean up local state via useCartSync
				for (const item of confirmedItems) {
					cart.removeItem(item.rowKey);
				}
				// Reload from DB to sync state
				await cart.loadFromDb();

				const outboundNo =
					res.data?.data?.header?.outbound_number || finalNumber || "";

				// 결과 모달 표시 (바로 이동하지 않음)
				setConfirmResult({
					outboundNumber: outboundNo,
					items: confirmedItems,
					warehouse:
						warehouses.find((w) => w.warehouse_code === selectedWarehouse)
							?.warehouse_name || selectedWarehouse,
					date: outboundDate,
				});
				setResultMsg(null);
			} else {
				setResultMsg(
					`오류: ${res.data?.message || "출고 등록에 실패했습니다."}`,
				);
			}
		} catch (err: unknown) {
			const msg =
				err instanceof Error ? err.message : "출고 등록에 실패했습니다.";
			setResultMsg(`오류: ${msg}`);
		} finally {
			setConfirming(false);
		}
	};

	/* ------------------------------------------------------------------ */
	/* Helpers                                                             */
	/* ------------------------------------------------------------------ */
	const selectedWarehouseName =
		warehouses.find((w) => w.warehouse_code === selectedWarehouse)
			?.warehouse_name || selectedWarehouse;

	const totalQty = selectedItemsList.reduce((s, i) => s + i.outbound_qty, 0);

	/* ------------------------------------------------------------------ */
	/* Render                                                              */
	/* ------------------------------------------------------------------ */
	return (
		<div className="flex flex-col gap-4 pb-4">
			<style>{`@keyframes cartMarquee { 0%,20% { transform: translateX(0); } 80%,100% { transform: translateX(calc(-100% + 100cqi)); } }`}</style>
			{/* ===== Header ===== */}
			<div className="flex items-center justify-between">
				<div className="flex items-center gap-3">
					<button
						onClick={() => router.back()}
						className="w-10 h-10 rounded-xl bg-white border border-gray-200 flex items-center justify-center text-gray-500 hover:bg-gray-50 active:scale-95 transition-all"
					>
						<svg
							className="w-5 h-5"
							fill="none"
							stroke="currentColor"
							strokeWidth={2}
							viewBox="0 0 24 24"
						>
							<path
								strokeLinecap="round"
								strokeLinejoin="round"
								d="M15.75 19.5L8.25 12l7.5-7.5"
							/>
						</svg>
					</button>
					<div>
						<h1 className="text-xl sm:text-2xl font-bold text-gray-900 tracking-tight">
							출고 장바구니
						</h1>
					</div>
				</div>

				{/* Confirm button (header only) */}
				<button
					onClick={handleConfirm}
					disabled={
						confirming ||
						selectedItemsList.length === 0
					}
					className="flex items-center gap-1.5 px-4 h-10 rounded-xl text-sm font-bold text-white active:scale-[0.98] transition-all disabled:opacity-40"
					style={{
						background:
							selectedItemsList.length > 0
								? "linear-gradient(to bottom, #34d399, #059669)"
								: "#d1d5db",
						boxShadow:
							selectedItemsList.length > 0
								? "0 4px 12px rgba(5,150,105,0.3)"
								: "none",
					}}
				>
					<svg
						className="w-4 h-4"
						fill="none"
						stroke="currentColor"
						strokeWidth={2.5}
						viewBox="0 0 24 24"
					>
						<path
							strokeLinecap="round"
							strokeLinejoin="round"
							d="M4.5 12.75l6 6 9-13.5"
						/>
					</svg>
					{confirming ? "처리중..." : "확정"}
				</button>
			</div>

			{/* ===== Info banner ===== */}
			<div className="bg-white rounded-xl border border-gray-100 shadow-sm p-3 sm:p-4">
				<div className="flex items-center gap-2 mb-3 pb-2 border-b border-gray-50">
					<span className="text-[11px] text-gray-400">{outboundDate}</span>
					{selectedWarehouseName && (
						<span className="text-[11px] text-gray-400">
							| {selectedWarehouseName}
						</span>
					)}
					<span className="ml-auto text-[11px] font-mono text-gray-400">
						{outboundNumber || "확정 시 자동생성"}
					</span>
				</div>

				{/* Info fields: 4 columns (거래처 + 출고일자 + 창고 + 출고번호) */}
				<div className="grid grid-cols-1 sm:grid-cols-4 gap-3">
					{/* 거래처 드롭다운 */}
					<div>
						<label className="text-[11px] font-semibold text-gray-400 mb-1 block">
							거래처
						</label>
						<select
							value={selectedCustomerFilter}
							onChange={(e) => setSelectedCustomerFilter(e.target.value)}
							disabled={customerList.length === 0}
							className="w-full px-3 py-2.5 border border-gray-200 rounded-lg text-sm outline-none focus:border-blue-400 focus:ring-1 focus:ring-blue-100 bg-white"
						>
							{customerList.length === 0 ? (
								<option value="">거래처 없음</option>
							) : (
								customerList.map((c) => (
									<option key={c.code} value={c.code}>
										{c.name}
									</option>
								))
							)}
						</select>
					</div>
					{/* Outbound date */}
					<div>
						<label className="text-[11px] font-semibold text-gray-400 mb-1 block">
							출고일자
						</label>
						<input
							type="date"
							value={outboundDate}
							onChange={(e) => setOutboundDate(e.target.value)}
							className="w-full px-3 py-2.5 border border-gray-200 rounded-lg text-sm outline-none focus:border-blue-400 focus:ring-1 focus:ring-blue-100 bg-white"
						/>
					</div>

					{/* Warehouse selector - card-style touch button */}
					<div>
						<label className="text-[11px] font-semibold text-gray-400 mb-1 block">
							창고
						</label>
						<button
							onClick={() => setWarehousePickerOpen(true)}
							className="w-full px-3 py-2.5 border border-gray-200 rounded-lg text-sm text-left outline-none hover:border-blue-300 transition-all bg-white flex items-center justify-between"
						>
							<span
								className={
									selectedWarehouse
										? "text-gray-900 font-medium"
										: "text-gray-400"
								}
							>
								{selectedWarehouseName || "창고 선택"}
							</span>
							<svg
								className="w-4 h-4 text-gray-400 shrink-0"
								fill="none"
								stroke="currentColor"
								strokeWidth={2}
								viewBox="0 0 24 24"
							>
								<path
									strokeLinecap="round"
									strokeLinejoin="round"
									d="M8.25 15l3.75-3.75L15.75 15"
								/>
							</svg>
						</button>
					</div>

					{/* Outbound number (readonly -- 확정 시점에 채번) */}
					<div>
						<label className="text-[11px] font-semibold text-gray-400 mb-1 block">
							출고번호
						</label>
						<div className="w-full px-3 py-2.5 border border-gray-200 rounded-lg text-sm bg-gray-50 font-mono">
							{outboundNumber ? (
								<span className="text-gray-700">{outboundNumber}</span>
							) : (
								<span className="text-gray-400">확정 시 자동생성</span>
							)}
						</div>
					</div>
				</div>
			</div>

			{/* ===== Select all bar (적재함 버튼 추가) ===== */}
			{items.length > 0 && (
				<div className="flex items-center gap-3 px-1">
					<button
						onClick={toggleSelectAll}
						className={`w-6 h-6 rounded border-2 flex items-center justify-center transition-all shrink-0 ${
							selectedItems.size === items.length
								? "bg-blue-500 border-blue-500"
								: "border-gray-300 hover:border-blue-400"
						}`}
					>
						{selectedItems.size === items.length && (
							<svg
								className="w-3.5 h-3.5 text-white"
								fill="none"
								stroke="currentColor"
								strokeWidth={3}
								viewBox="0 0 24 24"
							>
								<path
									strokeLinecap="round"
									strokeLinejoin="round"
									d="M4.5 12.75l6 6 9-13.5"
								/>
							</svg>
						)}
					</button>
					<span className="text-sm font-semibold text-gray-700">
						담은 품목 <span className="text-blue-600">{items.length}</span>
					</span>
					<button
						onClick={toggleSelectAll}
						className="px-2.5 py-1 rounded-md text-xs font-medium bg-blue-50 text-blue-600 border border-blue-200 hover:bg-blue-100 active:scale-95 transition-all"
					>
						{selectedItems.size === items.length ? "선택 해제" : "전체 선택"}
					</button>
					<div className="flex-1" />
					<button
						onClick={openLoadingModal}
						disabled={selectedItemsList.length === 0}
						className="flex items-center gap-1.5 px-4 h-10 rounded-xl text-sm font-bold bg-purple-50 text-purple-600 border border-purple-200 hover:bg-purple-100 active:scale-[0.98] transition-all disabled:opacity-40"
					>
						{"\uD83D\uDEA2"} 적재함
					</button>
				</div>
			)}

			{/* ===== Items list ===== */}
			{cart.loading ? (
				<div className="flex items-center justify-center py-16 text-sm text-gray-400">
					<svg
						className="animate-spin w-5 h-5 mr-2 text-blue-500"
						fill="none"
						viewBox="0 0 24 24"
					>
						<circle
							className="opacity-25"
							cx="12"
							cy="12"
							r="10"
							stroke="currentColor"
							strokeWidth="4"
						/>
						<path
							className="opacity-75"
							fill="currentColor"
							d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
						/>
					</svg>
					불러오는 중...
				</div>
			) : items.length === 0 ? (
				<div className="flex flex-col items-center justify-center py-16 text-gray-400">
					<svg
						className="w-16 h-16 mb-4 opacity-20"
						fill="none"
						stroke="currentColor"
						strokeWidth={1}
						viewBox="0 0 24 24"
					>
						<path
							strokeLinecap="round"
							strokeLinejoin="round"
							d="M2.25 3h1.386c.51 0 .955.343 1.087.835l.383 1.437M7.5 14.25a3 3 0 00-3 3h15.75m-12.75-3h11.218c1.121 0 2.002-.881 2.002-2.003V6.75m-14.22 0h14.22"
						/>
					</svg>
					<p className="text-sm font-medium text-gray-500 mb-1">
						담은 품목이 없습니다
					</p>
					<p className="text-xs text-gray-400 mb-4">
						출고 화면에서 품목을 담아주세요
					</p>
					<button
						onClick={() => router.push(backUrl)}
						className={`px-4 py-2.5 rounded-xl text-sm font-semibold text-white active:scale-95 transition-all ${COLOR_MAP.blue.buttonBg} ${COLOR_MAP.blue.buttonBgHover} shadow-[0_4px_12px_rgba(59,130,246,0.3)]`}
					>
						출고 화면으로 이동
					</button>
				</div>
			) : (
				<div className="flex flex-col gap-4">
					{(() => {
						/* 방식 A: 적재함 > 출고유형 그룹핑 */
						const loadingGroups = new Map<string, { loading_name: string; items: typeof filteredItems }>();
						const ungrouped: typeof filteredItems = [];

						filteredItems.forEach((item) => {
							if (item.loading_code) {
								const existing = loadingGroups.get(item.loading_code);
								if (existing) {
									existing.items.push(item);
								} else {
									loadingGroups.set(item.loading_code, {
										loading_name: item.loading_name || item.loading_code,
										items: [item],
									});
								}
							} else {
								ungrouped.push(item);
							}
						});

						const renderTypeGroupedCards = (groupItems: typeof filteredItems) => {
							const typeGroups = groupItems.reduce<Record<string, typeof filteredItems>>((acc, it) => {
								const type = it.outbound_type || "출고";
								if (!acc[type]) acc[type] = [];
								acc[type].push(it);
								return acc;
							}, {});
							return Object.entries(typeGroups).map(([type, typeItems]) => (
								<div key={type}>
									<div className="flex items-center gap-2 mb-2">
										<span className="text-xs font-bold text-gray-500">{type}</span>
										<div className="flex-1 h-px bg-gray-200" />
									</div>
									<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-3">
									{typeItems.map((item) => {
						return (
							<div
								key={item.id}
								className={`relative rounded-xl p-3 transition-all ${
									selectedItems.has(item.id)
										? "ring-2 ring-blue-500 border border-blue-500 bg-gradient-to-br from-blue-50/80 to-indigo-50/50"
										: "border border-gray-200 bg-white"
								}`}
							>

								{/* === Header row: checkbox + item code + item name + packaging button === */}
								<div className="flex items-center gap-1.5 mb-2.5 pb-2 border-b border-gray-100">
									{/* Checkbox */}
									<button
										onClick={() => toggleSelect(item.id)}
										className={`w-6 h-6 rounded border-2 flex items-center justify-center transition-all shrink-0 ${
											selectedItems.has(item.id)
												? "bg-blue-500 border-blue-500"
												: "border-gray-300 hover:border-blue-400"
										}`}
									>
										{selectedItems.has(item.id) && (
											<svg
												className="w-3.5 h-3.5 text-white"
												fill="none"
												stroke="currentColor"
												strokeWidth={3}
												viewBox="0 0 24 24"
											>
												<path
													strokeLinecap="round"
													strokeLinejoin="round"
													d="M4.5 12.75l6 6 9-13.5"
												/>
											</svg>
										)}
									</button>
									<span className="text-[11px] text-gray-400 font-medium shrink-0">
										{item.item_code}
									</span>
									<span className="text-[13px] font-semibold text-gray-900 flex-1 overflow-hidden whitespace-nowrap min-w-0" style={{ containerType: "inline-size" }}>
										<span
											className="inline-block"
											style={item.item_name.length > 15 ? { animation: "cartMarquee 3s ease-in-out infinite alternate" } : undefined}
										>{item.item_name}</span>
									</span>
								</div>

								{/* === Body row: image + info + action === */}
								<div className="flex gap-2.5">
									{/* Product image */}
									<div className="w-[56px] h-[56px] min-w-[56px] bg-gray-50 border border-gray-200 rounded-lg flex items-center justify-center shrink-0 overflow-hidden">
										{item.image ? (
											<img
												src={item.image}
												alt={item.item_name}
												className="w-full h-full object-cover rounded-lg"
											/>
										) : (
											<span className="text-2xl text-gray-300">
												{"\uD83D\uDCE6"}
											</span>
										)}
									</div>

									{/* Info columns */}
									<div className="flex-1 min-w-0 flex flex-col gap-[3px]">
										<div className="flex items-center gap-1.5 text-[11px]">
											<span className="text-gray-400 min-w-[45px] shrink-0">
												주문일
											</span>
											<span className="font-medium text-gray-700">
												{item.order_date || "-"}
											</span>
										</div>
										<div className="flex items-center gap-1.5 text-[11px]">
											<span className="text-gray-400 min-w-[45px] shrink-0">
												참조번호
											</span>
											<span className="font-medium text-gray-700 truncate">
												{item.reference_no || "-"}
											</span>
										</div>
										<div className="flex items-center gap-1.5 text-[11px]">
											<span className="text-gray-400 min-w-[45px] shrink-0">
												주문수량
											</span>
											<span className="font-medium text-gray-700">
												{item.order_qty.toLocaleString()}
											</span>
										</div>
										<div className="flex items-center gap-1.5 text-[11px]">
											<span className="text-gray-400 min-w-[45px] shrink-0">
												미출고
											</span>
											<span className="font-bold text-red-500">
												{item.remain_qty.toLocaleString()}
											</span>
										</div>
									</div>

									{/* Action column: qty display + delete button */}
									<div className="flex flex-col gap-1.5 items-stretch min-w-[80px] shrink-0">
										{/* Qty display - clickable to open simple keypad */}
										<button
											onClick={() => openNumpad(item)}
											className="flex items-center justify-center gap-1 px-2.5 py-2 rounded-md border transition-all bg-blue-50 border-blue-200 hover:bg-blue-100 cursor-pointer active:scale-95"
										>
											<span
												className="text-sm font-bold text-blue-700"
												style={{ fontVariantNumeric: "tabular-nums" }}
											>
												{item.outbound_qty.toLocaleString()}
											</span>
											<span className="text-[10px] text-gray-400">EA</span>
										</button>

										{/* Delete button */}
										<button
											onClick={() => handleRemove(item.rowKey)}
											className="flex items-center justify-center gap-1 px-2.5 py-2 rounded-md bg-red-500 text-white text-xs font-semibold hover:bg-red-600 active:scale-95 transition-all"
										>
											<svg
												className="w-3.5 h-3.5"
												fill="none"
												stroke="currentColor"
												strokeWidth={2}
												viewBox="0 0 24 24"
											>
												<path
													strokeLinecap="round"
													strokeLinejoin="round"
													d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
												/>
											</svg>
											삭제
										</button>
									</div>
								</div>

								{/* Packaging button - full width (포장 미완료 시만 표시) */}
								{!(item.packages && item.packages.length > 0) && (
									<div className="mt-1.5">
										<button
											onClick={() => openPackaging(item)}
											className="w-full flex items-center justify-center gap-1 px-2.5 py-2 rounded-md text-xs font-semibold active:scale-95 transition-all bg-amber-50 border border-amber-200 text-amber-700 hover:bg-amber-100"
										>
											<span>{"\uD83D\uDCE6"}</span>
											포장단위
										</button>
									</div>
								)}

								{/* === Package info (포장 등록 시 — 클릭하면 모달 열림) === */}
								{item.packages && item.packages.length > 0 && (() => {
									const packagedQty = item.packages.reduce(
										(s, p) => s + p.count * p.qtyPerUnit,
										0,
									);
									const unpacked = Math.max(0, item.outbound_qty - packagedQty);
									const isComplete = unpacked === 0;
									return (
									<div
										onClick={() => openPackaging(item)}
										className={`mt-2.5 px-3 py-2 border rounded-lg cursor-pointer active:scale-95 transition-all ${
											isComplete
												? "bg-gradient-to-r from-green-50 to-emerald-50 border-green-200"
												: "bg-gradient-to-r from-amber-50 to-orange-50 border-amber-200"
										}`}
									>
										<div className="flex items-center justify-between mb-1">
											<span
												className={`text-[10px] font-bold text-white px-2 py-0.5 rounded-full ${
													isComplete
														? "bg-gradient-to-r from-green-500 to-green-600"
														: "bg-gradient-to-r from-amber-500 to-orange-500"
												}`}
											>
												{isComplete ? "포장완료" : "부분포장"}
											</span>
											<span
												className={`text-[11px] font-semibold ${
													isComplete ? "text-green-600" : "text-amber-600"
												}`}
											>
												{packagedQty.toLocaleString()}{" "}
												EA
											</span>
										</div>
										<div className="grid grid-cols-2 gap-x-2 gap-y-0.5">
											{item.packages.map((pkg, idx) => (
												<div
													key={idx}
													className="flex items-center gap-1.5 text-[11px] text-gray-600"
												>
													<span>{pkg.unit.icon}</span>
													<span>
														{pkg.count}
														{pkg.unit.label} x {pkg.qtyPerUnit.toLocaleString()}EA
														= {(pkg.count * pkg.qtyPerUnit).toLocaleString()}EA
													</span>
												</div>
											))}
										</div>
										{!isComplete && (
											<div className="mt-1 pt-1 border-t border-amber-200 flex items-center justify-between text-[11px]">
												<span className="text-amber-700 font-medium">미포장</span>
												<span className="font-bold text-amber-700">
													{unpacked.toLocaleString()} EA
												</span>
											</div>
										)}
									</div>
									);
								})()}
							</div>
						);
					})}
							</div>
						</div>
					));
				};

						return (
							<>
								{Array.from(loadingGroups.entries()).map(([code, group]) => (
									<div key={code} className="rounded-2xl border-2 border-purple-200 bg-gradient-to-br from-purple-50/60 to-violet-50/40 p-3">
										<div className="flex items-center gap-2 mb-3">
											<span className="text-lg">{"\uD83D\uDEA2"}</span>
											<span className="text-sm font-bold text-purple-700">{group.loading_name}</span>
											<span className="text-[10px] text-purple-400 font-mono">{code}</span>
											<span className="text-[10px] text-purple-500 bg-purple-100 px-1.5 py-0.5 rounded-full">{group.items.length}건</span>
										</div>
										{renderTypeGroupedCards(group.items)}
									</div>
								))}
								{ungrouped.length > 0 && renderTypeGroupedCards(ungrouped)}
							</>
						);
					})()}
				</div>
			)}

			{/* ===== Result toast (only when message exists) ===== */}
			{resultMsg && (
				<div className="fixed bottom-6 left-1/2 -translate-x-1/2 z-40">
					<div
						className={`px-4 py-3 rounded-xl text-sm font-medium shadow-lg ${
							resultMsg.startsWith("오류")
								? "bg-red-50 text-red-700 border border-red-200"
								: "bg-green-50 text-green-700 border border-green-200"
						}`}
					>
						{resultMsg}
					</div>
				</div>
			)}

			{/* ===== Warehouse picker modal ===== */}
			{warehousePickerOpen && (
				<div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center">
					<div
						className="absolute inset-0 bg-black/50"
						onClick={() => setWarehousePickerOpen(false)}
					/>
					<div className="relative bg-white w-full sm:max-w-md sm:rounded-2xl rounded-t-2xl max-h-[80vh] flex flex-col shadow-2xl z-10 overflow-hidden">
						{/* Header */}
						<div className="flex items-center justify-between px-5 py-4 border-b border-gray-100">
							<h3 className="text-lg font-bold text-gray-900">창고 선택</h3>
							<button
								onClick={() => setWarehousePickerOpen(false)}
								className="w-8 h-8 rounded-lg bg-gray-100 flex items-center justify-center text-gray-500 hover:bg-gray-200 transition-colors"
							>
								<svg
									className="w-4 h-4"
									fill="none"
									stroke="currentColor"
									strokeWidth={2}
									viewBox="0 0 24 24"
								>
									<path
										strokeLinecap="round"
										strokeLinejoin="round"
										d="M6 18L18 6M6 6l12 12"
									/>
								</svg>
							</button>
						</div>

						{/* Warehouse list */}
						<div className="flex-1 overflow-y-auto p-4">
							{warehouses.length === 0 ? (
								<p className="text-center text-sm text-gray-400 py-8">
									등록된 창고가 없습니다
								</p>
							) : (
								<div className="flex flex-col gap-2">
									{warehouses.map((wh) => (
										<button
											key={wh.warehouse_code}
											onClick={() => {
												setSelectedWarehouse(wh.warehouse_code);
												setWarehousePickerOpen(false);
											}}
											className={`flex items-center gap-3 p-4 rounded-xl border transition-all active:scale-[0.98] text-left ${
												selectedWarehouse === wh.warehouse_code
													? "border-blue-400 bg-blue-50 shadow-sm"
													: "border-gray-200 bg-white hover:border-blue-300"
											}`}
										>
											<div
												className={`w-10 h-10 rounded-lg flex items-center justify-center shrink-0 ${
													selectedWarehouse === wh.warehouse_code
														? "bg-blue-500 text-white"
														: "bg-gray-100 text-gray-400"
												}`}
											>
												<svg
													className="w-5 h-5"
													fill="none"
													stroke="currentColor"
													strokeWidth={2}
													viewBox="0 0 24 24"
												>
													<path
														strokeLinecap="round"
														strokeLinejoin="round"
														d="M2.25 21h19.5m-18-18v18m10.5-18v18m6-13.5V21M6.75 6.75h.75m-.75 3h.75m-.75 3h.75m3-6h.75m-.75 3h.75m-.75 3h.75M6.75 21v-3.375c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21M3 3h12m-.75 4.5H21m-3.75 0h.008v.008h-.008v-.008zm0 3h.008v.008h-.008v-.008zm0 3h.008v.008h-.008v-.008z"
													/>
												</svg>
											</div>
											<div className="flex-1 min-w-0">
												<p className="text-sm font-semibold text-gray-900">
													{wh.warehouse_name}
												</p>
												<p className="text-[11px] text-gray-400">
													{wh.warehouse_code}
													{wh.warehouse_type ? ` | ${wh.warehouse_type}` : ""}
												</p>
											</div>
											{selectedWarehouse === wh.warehouse_code && (
												<svg
													className="w-5 h-5 text-blue-500 shrink-0"
													fill="none"
													stroke="currentColor"
													strokeWidth={2.5}
													viewBox="0 0 24 24"
												>
													<path
														strokeLinecap="round"
														strokeLinejoin="round"
														d="M4.5 12.75l6 6 9-13.5"
													/>
												</svg>
											)}
										</button>
									))}
								</div>
							)}
						</div>
					</div>
				</div>
			)}

			{/* ===== SimpleKeypad Modal (qty edit) ===== */}
			{numpadTarget && (
				<SimpleKeypadModal
					open={numpadOpen}
					onClose={() => {
						setNumpadOpen(false);
						setNumpadTarget(null);
					}}
					onConfirm={handleNumpadConfirm}
					maxQty={numpadTarget.remain_qty}
					itemName={numpadTarget.item_name}
					initialQty={numpadTarget.outbound_qty}
				/>
			)}

			{/* ===== NumberPad Modal (packaging) ===== */}
			{packagingTarget && (
				<NumberPadModal
					open={packagingOpen}
					onClose={() => {
						setPackagingOpen(false);
						setPackagingTarget(null);
					}}
					onConfirm={handlePackagingConfirm}
					maxQty={packagingTarget.outbound_qty}
					itemName={packagingTarget.item_name}
					itemNumber={packagingTarget.item_code}
					initialPackages={packagingTarget.packages}
				/>
			)}

			{/* ===== Loading Unit Modal (적재함 일괄 선택) ===== */}
			<LoadingUnitModal
				open={loadingModalOpen}
				onClose={() => setLoadingModalOpen(false)}
				onSelect={handleLoadingSelect}
				onClear={handleLoadingClear}
				pkgCodes={selectedPkgCodes}
				currentLoading={null}
			/>

			{/* ===== 출고 완료 결과 모달 ===== */}
			{confirmResult && (
				<div className="fixed inset-0 z-[70] flex items-center justify-center">
					<div className="absolute inset-0 bg-black/50" />
					<div className="relative bg-white rounded-2xl shadow-2xl w-full max-w-md mx-4 overflow-hidden z-10">
						{/* 헤더 */}
						<div
							className={`px-6 py-5 text-center ${COLOR_MAP.blue.buttonBg}`}
						>
							<div className="w-14 h-14 rounded-full bg-white/20 flex items-center justify-center mx-auto mb-3">
								<svg
									className="w-8 h-8 text-white"
									fill="none"
									stroke="currentColor"
									strokeWidth={2}
									viewBox="0 0 24 24"
								>
									<path
										strokeLinecap="round"
										strokeLinejoin="round"
										d="M4.5 12.75l6 6 9-13.5"
									/>
								</svg>
							</div>
							<h3 className="text-xl font-bold text-white">출고 처리 완료</h3>
							<p className="text-white/80 text-lg font-mono mt-1">
								{confirmResult.outboundNumber}
							</p>
						</div>

						{/* 처리 내역 */}
						<div className="px-6 py-4">
							<div className="flex items-center justify-between text-sm text-gray-500 mb-3">
								<span>
									창고:{" "}
									<span className="font-semibold text-gray-900">
										{confirmResult.warehouse}
									</span>
								</span>
								<span>{confirmResult.date}</span>
							</div>

							<div className="text-xs font-semibold text-gray-400 mb-2">
								처리된 품목 ({confirmResult.items.length}건)
							</div>
							<div className="max-h-[200px] overflow-y-auto flex flex-col gap-2">
								{confirmResult.items.map((item) => (
									<div
										key={item.id}
										className="flex items-center justify-between p-3 bg-green-50 rounded-xl border border-green-100"
									>
										<div className="flex-1 min-w-0">
											<p className="text-sm font-semibold text-gray-900 truncate">
												{item.item_name}
											</p>
											<p className="text-[11px] text-gray-400">
												{item.item_code}
											</p>
										</div>
										<span className="text-sm font-bold text-green-600 ml-3">
											{item.outbound_qty?.toLocaleString()} EA
										</span>
									</div>
								))}
							</div>
						</div>

						{/* 확인 버튼 */}
						<div className="px-6 py-4 border-t border-gray-100">
							<button
								onClick={() => {
									setConfirmResult(null);
									router.push(companyPath("/pop/outbound"));
								}}
								className={`w-full h-12 rounded-xl text-white font-bold text-base active:scale-[0.98] transition-all ${COLOR_MAP.blue.buttonBg} ${COLOR_MAP.blue.buttonBgHover} shadow-[0_4px_12px_rgba(59,130,246,0.3)]`}
							>
								확인
							</button>
						</div>
					</div>
				</div>
			)}
		</div>
	);
}
