"use client";

import {
  Box,
  Button,
  Stack,
  TextField,
  Typography,
  Alert,
  CircularProgress,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  Paper,
  Checkbox,
  TablePagination,
  Modal,
  Chip,
} from "@mui/material";
import dayjs from 'dayjs';
import TestQrCodeProvider from '../QrCodeScannerProvider/TestQrCodeProvider';
import { fetchLotDetail } from "@/app/api/inventory/actions";
import React, { useCallback, useEffect, useState, useRef, useMemo, startTransition } from "react";
import { useTranslation } from "react-i18next";
import { useRouter } from "next/navigation";
import {
  updateStockOutLineStatus,
  createStockOutLine,
  updateStockOutLine,
  recordPickExecutionIssue,
  fetchFGPickOrders, //  Add this import
  FGPickOrderResponse, 
  stockReponse,
  PickExecutionIssueData,
  checkPickOrderCompletion,
  fetchAllPickOrderLotsHierarchical,
  PickOrderCompletionResponse,
  checkAndCompletePickOrderByConsoCode,
  updateSuggestedLotLineId,
  updateStockOutLineStatusByQRCodeAndLotNo,
  confirmLotSubstitution,
  fetchDoPickOrderDetail,  //  必须添加
  DoPickOrderDetail,  //  必须添加
  fetchFGPickOrdersByUserId ,
  batchQrSubmit,
  batchSubmitList,  // 添加：导入 batchSubmitList
  batchSubmitListRequest,  // 添加：导入类型
  batchSubmitListLineRequest,
  batchScan,
  BatchScanRequest,
  BatchScanLineRequest,
} from "@/app/api/pickOrder/actions";

import FGPickOrderInfoCard from "./FGPickOrderInfoCard";
import LotConfirmationModal from "./LotConfirmationModal";
//import { fetchItem } from "@/app/api/settings/item";
import { updateInventoryLotLineStatus, analyzeQrCode } from "@/app/api/inventory/actions";
import { fetchNameList, NameList } from "@/app/api/user/actions";
import {
  FormProvider,
  useForm,
} from "react-hook-form";
import SearchBox, { Criterion } from "../SearchBox";
import { CreateStockOutLine } from "@/app/api/pickOrder/actions";
import { updateInventoryLotLineQuantities } from "@/app/api/inventory/actions";
import QrCodeIcon from '@mui/icons-material/QrCode';
import { useQrCodeScannerContext } from '../QrCodeScannerProvider/QrCodeScannerProvider';
import { useSession } from "next-auth/react";
import { SessionWithTokens } from "@/config/authConfig";
import { fetchStockInLineInfo } from "@/app/api/po/actions";
import GoodPickExecutionForm from "./GoodPickExecutionForm";
import FGPickOrderCard from "./FGPickOrderCard"; 
import LinearProgressWithLabel from "../common/LinearProgressWithLabel";
import ScanStatusAlert from "../common/ScanStatusAlert";
interface Props {
  filterArgs: Record<string, any>;
  onSwitchToRecordTab?: () => void;
  onRefreshReleasedOrderCount?: () => void;
}

/** 同物料多行时，优先对「有建议批次号」的行做替换，避免误选「无批次/不足」行 */
function pickExpectedLotForSubstitution(activeSuggestedLots: any[]): any | null {
  if (!activeSuggestedLots?.length) return null;
  const withLotNo = activeSuggestedLots.filter(
    (l) => l.lotNo != null && String(l.lotNo).trim() !== ""
  );
  if (withLotNo.length === 1) return withLotNo[0];
  if (withLotNo.length > 1) {
    const pending = withLotNo.find(
      (l) => (l.stockOutLineStatus || "").toLowerCase() === "pending"
    );
    return pending || withLotNo[0];
  }
  return activeSuggestedLots[0];
}

//  QR Code Modal Component (from LotTable)
const QrCodeModal: React.FC<{
  open: boolean;
  onClose: () => void;
  lot: any | null;
  onQrCodeSubmit: (lotNo: string) => void;
  combinedLotData: any[]; //  Add this prop
  lotConfirmationOpen: boolean;
}> = ({ open, onClose, lot, onQrCodeSubmit, combinedLotData,lotConfirmationOpen = false }) => {
  const { t } = useTranslation("pickOrder");
  const { values: qrValues, isScanning, startScan, stopScan, resetScan } = useQrCodeScannerContext();
  const [manualInput, setManualInput] = useState<string>('');

  const [manualInputSubmitted, setManualInputSubmitted] = useState<boolean>(false);
  const [manualInputError, setManualInputError] = useState<boolean>(false);
  const [isProcessingQr, setIsProcessingQr] = useState<boolean>(false);
  const [qrScanFailed, setQrScanFailed] = useState<boolean>(false);
  const [qrScanSuccess, setQrScanSuccess] = useState<boolean>(false);
  
  const [processedQrCodes, setProcessedQrCodes] = useState<Set<string>>(new Set());
  const [scannedQrResult, setScannedQrResult] = useState<string>('');
  const [fgPickOrder, setFgPickOrder] = useState<FGPickOrderResponse | null>(null);
  const fetchingRef = useRef<Set<number>>(new Set()); 
  // Process scanned QR codes
  useEffect(() => {
    // ✅ Don't process if modal is not open
    if (!open) {
      return;
    }
    
    // ✅ Don't process if lot confirmation modal is open
    if (lotConfirmationOpen) {
      console.log("Lot confirmation modal is open, skipping QrCodeModal processing...");
      return;
    }
    
    if (qrValues.length > 0 && lot && !isProcessingQr && !qrScanSuccess) {
      const latestQr = qrValues[qrValues.length - 1];
      
      if (processedQrCodes.has(latestQr)) {
        console.log("QR code already processed, skipping...");
        return;
      }
      
      try {
        const qrData = JSON.parse(latestQr);
        
        if (qrData.stockInLineId && qrData.itemId) {
          // ✅ Check if we're already fetching this stockInLineId
          if (fetchingRef.current.has(qrData.stockInLineId)) {
            console.log(`  [QR MODAL] Already fetching stockInLineId: ${qrData.stockInLineId}, skipping duplicate call`);
            return;
          }
          
          setProcessedQrCodes(prev => new Set(prev).add(latestQr));
          setIsProcessingQr(true);
          setQrScanFailed(false);
          
          // ✅ Mark as fetching
          fetchingRef.current.add(qrData.stockInLineId);
          
          const fetchStartTime = performance.now();
          console.log(`  [QR MODAL] Starting fetchStockInLineInfo for stockInLineId: ${qrData.stockInLineId}`);
          
          fetchStockInLineInfo(qrData.stockInLineId)
            .then((stockInLineInfo) => {
              // ✅ Remove from fetching set
              fetchingRef.current.delete(qrData.stockInLineId);
              
              // ✅ Check again if modal is still open and lot confirmation is not open
              if (!open || lotConfirmationOpen) {
                console.log("Modal state changed, skipping result processing");
                return;
              }
              
              const fetchTime = performance.now() - fetchStartTime;
              console.log(`  [QR MODAL] fetchStockInLineInfo time: ${fetchTime.toFixed(2)}ms (${(fetchTime / 1000).toFixed(3)}s)`);
              console.log("Stock in line info:", stockInLineInfo);
              setScannedQrResult(stockInLineInfo.lotNo || 'Unknown lot number');
              
              if (stockInLineInfo.lotNo === lot.lotNo) {
                console.log(` QR Code verified for lot: ${lot.lotNo}`);
                setQrScanSuccess(true);
                onQrCodeSubmit(lot.lotNo);
               // onClose();
                //resetScan();
              } else {
                console.log(`  QR Code mismatch. Expected: ${lot.lotNo}, Got: ${stockInLineInfo.lotNo}`);
                setQrScanFailed(true);
                setManualInputError(true);
                setManualInputSubmitted(true);
              }
            })
            .catch((error) => {
              // ✅ Remove from fetching set
              fetchingRef.current.delete(qrData.stockInLineId);
              
              // ✅ Check again if modal is still open
              if (!open || lotConfirmationOpen) {
                console.log("Modal state changed, skipping error handling");
                return;
              }
              
              const fetchTime = performance.now() - fetchStartTime;
              console.error(`❌ [QR MODAL] fetchStockInLineInfo failed after ${fetchTime.toFixed(2)}ms:`, error);
              setScannedQrResult('Error fetching data');
              setQrScanFailed(true);
              setManualInputError(true);
              setManualInputSubmitted(true);
            })
            .finally(() => {
              setIsProcessingQr(false);
            });
        } else {
          const qrContent = latestQr.replace(/[{}]/g, '');
          setScannedQrResult(qrContent);
          
          if (qrContent === lot.lotNo) {
            setQrScanSuccess(true);
            onQrCodeSubmit(lot.lotNo);
            onClose();
            resetScan();
          } else {
            setQrScanFailed(true);
            setManualInputError(true);
            setManualInputSubmitted(true);
          }
        }
      } catch (error) {
        console.log("QR code is not JSON format, trying direct comparison");
        const qrContent = latestQr.replace(/[{}]/g, '');
        setScannedQrResult(qrContent);
        
        if (qrContent === lot.lotNo) {
          setQrScanSuccess(true);
          onQrCodeSubmit(lot.lotNo);
          onClose();
          resetScan();
        } else {
          setQrScanFailed(true);
          setManualInputError(true);
          setManualInputSubmitted(true);
        }
      }
    }
  }, [qrValues, lot, onQrCodeSubmit, onClose, resetScan, isProcessingQr, qrScanSuccess, processedQrCodes, lotConfirmationOpen, open]);

  // Clear states when modal opens
  useEffect(() => {
    if (open) {
      setManualInput('');
      setManualInputSubmitted(false);
      setManualInputError(false);
      setIsProcessingQr(false);
      setQrScanFailed(false);
      setQrScanSuccess(false);
      setScannedQrResult('');
      setProcessedQrCodes(new Set());
    }
  }, [open]);

  useEffect(() => {
    if (lot) {
      setManualInput('');
      setManualInputSubmitted(false);
      setManualInputError(false);
      setIsProcessingQr(false);
      setQrScanFailed(false);
      setQrScanSuccess(false);
      setScannedQrResult('');
      setProcessedQrCodes(new Set());
    }
  }, [lot]);

  // Auto-submit manual input when it matches
  useEffect(() => {
    if (manualInput.trim() === lot?.lotNo && manualInput.trim() !== '' && !qrScanFailed && !qrScanSuccess) {
      console.log(' Auto-submitting manual input:', manualInput.trim());
      
      const timer = setTimeout(() => {
        setQrScanSuccess(true);
        onQrCodeSubmit(lot.lotNo);
        onClose();
        setManualInput('');
        setManualInputError(false);
        setManualInputSubmitted(false);
      }, 200);
      
      return () => clearTimeout(timer);
    }
  }, [manualInput, lot, onQrCodeSubmit, onClose, qrScanFailed, qrScanSuccess]);

  const handleManualSubmit = () => {
    if (manualInput.trim() === lot?.lotNo) {
      setQrScanSuccess(true);
      onQrCodeSubmit(lot.lotNo);
      onClose();
      setManualInput('');
    } else {
      setQrScanFailed(true);
      setManualInputError(true);
      setManualInputSubmitted(true);
    }
  };

  useEffect(() => {
    if (open) {
      startScan();
    }
  }, [open, startScan]);

  return (
    <Modal open={open} onClose={onClose}>
      <Box sx={{
        position: 'absolute',
        top: '50%',
        left: '50%',
        transform: 'translate(-50%, -50%)',
        bgcolor: 'background.paper',
        p: 3,
        borderRadius: 2,
        minWidth: 400,
      }}>
        <Typography variant="h6" gutterBottom>
          {t("QR Code Scan for Lot")}: {lot?.lotNo}
        </Typography>
        
        {isProcessingQr && (
          <Box sx={{ mb: 2, p: 2, backgroundColor: '#e3f2fd', borderRadius: 1 }}>
            <Typography variant="body2" color="primary">
               {t("Processing QR code...")}
            </Typography>
          </Box>
        )}
        
        <Box sx={{ mb: 2 }}>
          <Typography variant="body2" gutterBottom>
            <strong>{t("Manual Input")}:</strong>
          </Typography>
          <TextField
            fullWidth
            size="small"
            value={manualInput}
            onChange={(e) => {
              setManualInput(e.target.value);
              if (qrScanFailed || manualInputError) {
                setQrScanFailed(false);
                setManualInputError(false);
                setManualInputSubmitted(false);
              }
            }}
            sx={{ mb: 1 }}
            error={manualInputSubmitted && manualInputError}
            helperText={
              manualInputSubmitted && manualInputError
                ? `${t("The input is not the same as the expected lot number.")}`
                : ''
            }
          />
          <Button
            variant="contained"
            onClick={handleManualSubmit}
            disabled={!manualInput.trim()}
            size="small"
            color="primary"
          >
            {t("Submit")}
          </Button>
        </Box>

        {qrValues.length > 0 && (
          <Box sx={{ 
            mb: 2, 
            p: 2, 
            backgroundColor: qrScanFailed ? '#ffebee' : qrScanSuccess ? '#e8f5e8' : '#f5f5f5', 
            borderRadius: 1 
          }}>
            <Typography variant="body2" color={qrScanFailed ? 'error' : qrScanSuccess ? 'success' : 'text.secondary'}>
              <strong>{t("QR Scan Result:")}</strong> {scannedQrResult}
            </Typography>

            {qrScanSuccess && (
              <Typography variant="caption" color="success" display="block">
                 {t("Verified successfully!")}
              </Typography>
            )}
          </Box>
        )}

        <Box sx={{ mt: 2, textAlign: 'right' }}>
          <Button onClick={onClose} variant="outlined">
            {t("Cancel")}
          </Button>
        </Box>
      </Box>
    </Modal>
  );
};
const ManualLotConfirmationModal: React.FC<{
  open: boolean;
  onClose: () => void;
  onConfirm: (expectedLotNo: string, scannedLotNo: string) => void;
  expectedLot: {
    lotNo: string;
    itemCode: string;
    itemName: string;
  } | null;
  scannedLot: {
    lotNo: string;
    itemCode: string;
    itemName: string;
  } | null;
  isLoading?: boolean;
}> = ({ open, onClose, onConfirm, expectedLot, scannedLot, isLoading = false }) => {
  const { t } = useTranslation("pickOrder");
  const [expectedLotInput, setExpectedLotInput] = useState<string>('');
  const [scannedLotInput, setScannedLotInput] = useState<string>('');
  const [error, setError] = useState<string>('');

  // 当模态框打开时，预填充输入框
  useEffect(() => {
    if (open) {
      setExpectedLotInput(expectedLot?.lotNo || '');
      setScannedLotInput(scannedLot?.lotNo || '');
      setError('');
    }
  }, [open, expectedLot, scannedLot]);

  const handleConfirm = () => {
    if (!expectedLotInput.trim() || !scannedLotInput.trim()) {
      setError(t("Please enter both expected and scanned lot numbers."));
      return;
    }
    
    if (expectedLotInput.trim() === scannedLotInput.trim()) {
      setError(t("Expected and scanned lot numbers cannot be the same."));
      return;
    }

    onConfirm(expectedLotInput.trim(), scannedLotInput.trim());
  };

  return (
    <Modal open={open} onClose={onClose}>
      <Box sx={{
        position: 'absolute',
        top: '50%',
        left: '50%',
        transform: 'translate(-50%, -50%)',
        bgcolor: 'background.paper',
        p: 3,
        borderRadius: 2,
        minWidth: 500,
      }}>
        <Typography variant="h6" gutterBottom color="warning.main">
          {t("Manual Lot Confirmation")}
        </Typography>
        
        <Box sx={{ mb: 2 }}>
          <Typography variant="body2" gutterBottom>
            <strong>{t("Expected Lot Number")}:</strong>
          </Typography>
          <TextField
            fullWidth
            size="small"
            value={expectedLotInput}
            onChange={(e) => {
              setExpectedLotInput(e.target.value);
              setError('');
            }}
            placeholder={expectedLot?.lotNo || t("Enter expected lot number")}
            sx={{ mb: 2 }}
            error={!!error && !expectedLotInput.trim()}
          />
        </Box>

        <Box sx={{ mb: 2 }}>
          <Typography variant="body2" gutterBottom>
            <strong>{t("Scanned Lot Number")}:</strong>
          </Typography>
          <TextField
            fullWidth
            size="small"
            value={scannedLotInput}
            onChange={(e) => {
              setScannedLotInput(e.target.value);
              setError('');
            }}
            placeholder={scannedLot?.lotNo || t("Enter scanned lot number")}
            sx={{ mb: 2 }}
            error={!!error && !scannedLotInput.trim()}
          />
        </Box>

        {error && (
          <Box sx={{ mb: 2, p: 1, backgroundColor: '#ffebee', borderRadius: 1 }}>
            <Typography variant="body2" color="error">
              {error}
            </Typography>
          </Box>
        )}

        <Box sx={{ mt: 2, display: 'flex', justifyContent: 'flex-end', gap: 2 }}>
          <Button onClick={onClose} variant="outlined" disabled={isLoading}>
            {t("Cancel")}
          </Button>
          <Button 
            onClick={handleConfirm} 
            variant="contained" 
            color="warning"
            disabled={isLoading || !expectedLotInput.trim() || !scannedLotInput.trim()}
          >
            {isLoading ? t("Processing...") : t("Confirm")}
          </Button>
        </Box>
      </Box>
    </Modal>
  );
};

/** 過期批號（未換有效批前）：與 noLot 類似——單筆/批量預設提交量為 0，除非 Issue 改數 */
function isLotAvailabilityExpired(lot: any): boolean {
  return String(lot?.lotAvailability || "").toLowerCase() === "expired";
}

/** inventory_lot_line.status = unavailable（API 可能用 lotAvailability 或 lotStatus） */
function isInventoryLotLineUnavailable(lot: any): boolean {
  if (!lot) return false;
  if (lot.lotAvailability === "status_unavailable") return true;
  return String(lot.lotStatus || "").toLowerCase() === "unavailable";
}

/** Issue「改數」未寫入 SOL，刷新/換頁後需靠 session 還原，否則 Qty will submit 會回到 req */
const FG_ISSUE_PICKED_KEY = (doPickOrderId: number) =>
  `fpsms-fg-issuePickedQty:${doPickOrderId}`;

function loadIssuePickedMap(doPickOrderId: number): Record<number, number> {
  if (typeof window === "undefined" || !doPickOrderId) return {};
  try {
    const raw = sessionStorage.getItem(FG_ISSUE_PICKED_KEY(doPickOrderId));
    if (!raw) return {};
    const parsed = JSON.parse(raw) as Record<string, number>;
    const out: Record<number, number> = {};
    Object.entries(parsed).forEach(([k, v]) => {
      const n = Number(v);
      if (!Number.isNaN(n)) out[Number(k)] = n;
    });
    return out;
  } catch {
    return {};
  }
}

function saveIssuePickedMap(doPickOrderId: number, map: Record<number, number>) {
  if (typeof window === "undefined" || !doPickOrderId) return;
  try {
    sessionStorage.setItem(FG_ISSUE_PICKED_KEY(doPickOrderId), JSON.stringify(map));
  } catch {
    // quota / private mode
  }
}

const PickExecution: React.FC<Props> = ({ filterArgs, onSwitchToRecordTab, onRefreshReleasedOrderCount }) => {
  const { t } = useTranslation("pickOrder");
  const router = useRouter();
  const { data: session } = useSession() as { data: SessionWithTokens | null };
  const [doPickOrderDetail, setDoPickOrderDetail] = useState<DoPickOrderDetail | null>(null);
const [selectedPickOrderId, setSelectedPickOrderId] = useState<number | null>(null);
const [pickOrderSwitching, setPickOrderSwitching] = useState(false);
  const currentUserId = session?.id ? parseInt(session.id) : undefined;
  const [allLotsCompleted, setAllLotsCompleted] = useState(false);
  const [combinedLotData, setCombinedLotData] = useState<any[]>([]);
  const [combinedDataLoading, setCombinedDataLoading] = useState(false);
  const [originalCombinedData, setOriginalCombinedData] = useState<any[]>([]);
  // issue form 里填的 actualPickQty（用于 batch submit 只提交实际拣到数量，而不是补拣到 required）
  const [issuePickedQtyBySolId, setIssuePickedQtyBySolId] = useState<Record<number, number>>({});
  const applyLocalStockOutLineUpdate = useCallback((
    stockOutLineId: number,
    status: string,
    actualPickQty?: number
  ) => {
    setCombinedLotData(prev => prev.map((lot) => {
      if (Number(lot.stockOutLineId) !== Number(stockOutLineId)) return lot;
      return {
        ...lot,
        stockOutLineStatus: status,
        ...(typeof actualPickQty === "number"
          ? { actualPickQty, stockOutLineQty: actualPickQty }
          : {}),
      };
    }));
  }, []);
  // 防止重复点击（Submit / Just Completed / Issue）
  const [actionBusyBySolId, setActionBusyBySolId] = useState<Record<number, boolean>>({});
  
  const { values: qrValues, isScanning, startScan, stopScan, resetScan } = useQrCodeScannerContext();
  
  const [qrScanInput, setQrScanInput] = useState<string>('');
  const [qrScanError, setQrScanError] = useState<boolean>(false);
  const [qrScanErrorMsg, setQrScanErrorMsg] = useState<string>('');
  const [qrScanSuccess, setQrScanSuccess] = useState<boolean>(false);
  const [manualLotConfirmationOpen, setManualLotConfirmationOpen] = useState(false);
  const [pickQtyData, setPickQtyData] = useState<Record<string, number>>({});
  const [searchQuery, setSearchQuery] = useState<Record<string, any>>({});

  const [paginationController, setPaginationController] = useState({
    pageNum: 0,
    pageSize: -1,
  });

  const [usernameList, setUsernameList] = useState<NameList[]>([]);

  const initializationRef = useRef(false);
  const autoAssignRef = useRef(false);

  const formProps = useForm();
  const errors = formProps.formState.errors;

  //  QR scanner states (always-on, no modal)
  const [selectedLotForQr, setSelectedLotForQr] = useState<any | null>(null);
  const [lotConfirmationOpen, setLotConfirmationOpen] = useState(false);
  const [lotConfirmationError, setLotConfirmationError] = useState<string | null>(null);
const [expectedLotData, setExpectedLotData] = useState<any>(null);
const [scannedLotData, setScannedLotData] = useState<any>(null);
const [isConfirmingLot, setIsConfirmingLot] = useState(false);
  //  Add GoodPickExecutionForm states
  const [pickExecutionFormOpen, setPickExecutionFormOpen] = useState(false);
  const [selectedLotForExecutionForm, setSelectedLotForExecutionForm] = useState<any | null>(null);
  const [fgPickOrders, setFgPickOrders] = useState<FGPickOrderResponse[]>([]);

  const [fgPickOrdersLoading, setFgPickOrdersLoading] = useState(false);
    //  Add these missing state variables after line 352
    const [isManualScanning, setIsManualScanning] = useState<boolean>(false);
    // Track processed QR codes by itemId+stockInLineId combination for better lot confirmation handling
    const [processedQrCombinations, setProcessedQrCombinations] = useState<Map<number, Set<number>>>(new Map());
    const [processedQrCodes, setProcessedQrCodes] = useState<Set<string>>(new Set());
    const [lastProcessedQr, setLastProcessedQr] = useState<string>('');
    const [isRefreshingData, setIsRefreshingData] = useState<boolean>(false);
    const [isSubmittingAll, setIsSubmittingAll] = useState<boolean>(false);
    
    // Cache for fetchStockInLineInfo API calls to avoid redundant requests
    const stockInLineInfoCache = useRef<Map<number, { lotNo: string | null; timestamp: number }>>(new Map());
    const CACHE_TTL = 60000; // 60 seconds cache TTL
    const abortControllerRef = useRef<AbortController | null>(null);
    const qrProcessingTimeoutRef = useRef<NodeJS.Timeout | null>(null);
    
    // Use refs for processed QR tracking to avoid useEffect dependency issues and delays
    const processedQrCodesRef = useRef<Set<string>>(new Set());
    const lastProcessedQrRef = useRef<string>('');
    
    // Store callbacks in refs to avoid useEffect dependency issues
    const processOutsideQrCodeRef = useRef<
      ((latestQr: string, qrScanCountAtInvoke?: number) => Promise<void>) | null
    >(null);
    const resetScanRef = useRef<(() => void) | null>(null);
    const lotConfirmOpenedQrCountRef = useRef<number>(0);
    const lotConfirmLastQrRef = useRef<string>('');
    const lotConfirmSkipNextScanRef = useRef<boolean>(false);
    const lotConfirmOpenedAtRef = useRef<number>(0);
    
 
  
  //  Handle QR code button click
  const handleQrCodeClick = (pickOrderId: number) => {
    console.log(`QR Code clicked for pick order ID: ${pickOrderId}`);
    // TODO: Implement QR code functionality
  };
  const progress = useMemo(() => {
    if (combinedLotData.length === 0) {
      return { completed: 0, total: 0 };
    }

    // 與 allItemsReady 一致：noLot / 過期 / unavailable 的 pending 也算「已面對該行」可收尾
    const nonPendingCount = combinedLotData.filter((lot) => {
      const status = lot.stockOutLineStatus?.toLowerCase();
      if (status !== "pending") return true;
      if (lot.noLot === true || isLotAvailabilityExpired(lot) || isInventoryLotLineUnavailable(lot)) return true;
      return false;
    }).length;

    return {
      completed: nonPendingCount,
      total: combinedLotData.length,
    };
  }, [combinedLotData]);

  
  // Cached version of fetchStockInLineInfo to avoid redundant API calls
  const fetchStockInLineInfoCached = useCallback(async (stockInLineId: number): Promise<{ lotNo: string | null }> => {
    const now = Date.now();
    const cached = stockInLineInfoCache.current.get(stockInLineId);
    
    // Return cached value if still valid
    if (cached && (now - cached.timestamp) < CACHE_TTL) {
      console.log(`✅ [CACHE HIT] Using cached stockInLineInfo for ${stockInLineId}`);
      return { lotNo: cached.lotNo };
    }
    
    // Cancel previous request if exists
    if (abortControllerRef.current) {
      abortControllerRef.current.abort();
    }
    
    // Create new abort controller for this request
    const abortController = new AbortController();
    abortControllerRef.current = abortController;
    
    try {
      console.log(`  [CACHE MISS] Fetching stockInLineInfo for ${stockInLineId}`);
      const stockInLineInfo = await fetchStockInLineInfo(stockInLineId);
      
      // Store in cache
      stockInLineInfoCache.current.set(stockInLineId, {
        lotNo: stockInLineInfo.lotNo || null,
        timestamp: now
      });
      
      // Limit cache size to prevent memory leaks
      if (stockInLineInfoCache.current.size > 100) {
        const firstKey = stockInLineInfoCache.current.keys().next().value;
        if (firstKey !== undefined) {
          stockInLineInfoCache.current.delete(firstKey);
        }
      }
      
      return { lotNo: stockInLineInfo.lotNo || null };
    } catch (error: any) {
      if (error.name === 'AbortError') {
        console.log(`  [CACHE] Request aborted for ${stockInLineId}`);
        throw error;
      }
      console.error(`❌ [CACHE] Error fetching stockInLineInfo for ${stockInLineId}:`, error);
      throw error;
    }
  }, []);

  const handleLotMismatch = useCallback((expectedLot: any, scannedLot: any, qrScanCountAtOpen?: number) => {
    const mismatchStartTime = performance.now();
    console.log(`  [HANDLE LOT MISMATCH START]`);
    console.log(`  Start time: ${new Date().toISOString()}`);
    console.log("Lot mismatch detected:", { expectedLot, scannedLot });

    lotConfirmOpenedQrCountRef.current =
      typeof qrScanCountAtOpen === "number" ? qrScanCountAtOpen : 1;
    
    // ✅ Use setTimeout to avoid flushSync warning - schedule modal update in next tick
    const setTimeoutStartTime = performance.now();
    console.time('setLotConfirmationOpen');
    setTimeout(() => {
      const setStateStartTime = performance.now();
      setExpectedLotData(expectedLot);
      setScannedLotData({
        ...scannedLot,
        lotNo: scannedLot.lotNo || null,
      });
      // The QR that opened modal must NOT be treated as confirmation rescan.
      lotConfirmSkipNextScanRef.current = true;
      lotConfirmOpenedAtRef.current = Date.now();
      setLotConfirmationOpen(true);
      const setStateTime = performance.now() - setStateStartTime;
      console.timeEnd('setLotConfirmationOpen');
      console.log(`  [HANDLE LOT MISMATCH] Modal state set to open (setState time: ${setStateTime.toFixed(2)}ms)`);
      console.log(`✅ [HANDLE LOT MISMATCH] Modal state set to open`);
    }, 0);
    const setTimeoutTime = performance.now() - setTimeoutStartTime;
    console.log(`  [PERF] setTimeout scheduling time: ${setTimeoutTime.toFixed(2)}ms`);
    
    // ✅ Fetch lotNo in background ONLY for display purposes (using cached version)
    if (!scannedLot.lotNo && scannedLot.stockInLineId) {
      const stockInLineId = scannedLot.stockInLineId;
      if (typeof stockInLineId !== 'number') {
        console.warn(`  [HANDLE LOT MISMATCH] Invalid stockInLineId: ${stockInLineId}`);
        return;
      }
      console.log(`  [HANDLE LOT MISMATCH] Fetching lotNo in background (stockInLineId: ${stockInLineId})`);
      const fetchStartTime = performance.now();
      
      fetchStockInLineInfoCached(stockInLineId)
        .then((stockInLineInfo) => {
          const fetchTime = performance.now() - fetchStartTime;
          console.log(`  [HANDLE LOT MISMATCH] fetchStockInLineInfoCached time: ${fetchTime.toFixed(2)}ms (${(fetchTime / 1000).toFixed(3)}s)`);
          
          const updateStateStartTime = performance.now();
          startTransition(() => {
            setScannedLotData((prev: any) => ({
              ...prev,
              lotNo: stockInLineInfo.lotNo || null,
            }));
          });
          const updateStateTime = performance.now() - updateStateStartTime;
          console.log(`  [PERF] Update scanned lot data time: ${updateStateTime.toFixed(2)}ms`);
          
          const totalTime = performance.now() - mismatchStartTime;
          console.log(`  [HANDLE LOT MISMATCH] Background fetch completed: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`);
        })
        .catch((error) => {
          if (error.name !== 'AbortError') {
            const fetchTime = performance.now() - fetchStartTime;
            console.error(`❌ [HANDLE LOT MISMATCH] fetchStockInLineInfoCached failed after ${fetchTime.toFixed(2)}ms:`, error);
          }
        });
    } else {
      const totalTime = performance.now() - mismatchStartTime;
      console.log(`  [HANDLE LOT MISMATCH END] Total time: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`);
    }
  }, [fetchStockInLineInfoCached]);
  const checkAllLotsCompleted = useCallback((lotData: any[]) => {
    if (lotData.length === 0) {
      setAllLotsCompleted(false);
      return false;
    }

    // Filter out rejected lots
    const nonRejectedLots = lotData.filter(lot => 
      lot.lotAvailability !== 'rejected' && 
      lot.stockOutLineStatus !== 'rejected'
    );

    if (nonRejectedLots.length === 0) {
      setAllLotsCompleted(false);
      return false;
    }

    // Check if all non-rejected lots are completed
    const allCompleted = nonRejectedLots.every(lot => 
      lot.stockOutLineStatus === 'completed'
    );

    setAllLotsCompleted(allCompleted);
    return allCompleted;
  }, []);
// 在 fetchAllCombinedLotData 函数中（约 446-684 行）

const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdOverride?: number) => {
  setCombinedDataLoading(true);
  try {
    const userIdToUse = userId || currentUserId;
    
    console.log("  fetchAllCombinedLotData called with userId:", userIdToUse);
    
    if (!userIdToUse) {
      console.warn("⚠️ No userId available, skipping API call");
      setCombinedLotData([]);
      setOriginalCombinedData([]);
      setAllLotsCompleted(false);
      setIssuePickedQtyBySolId({});
      return;
    }
    
    //  获取新结构的层级数据
    const hierarchicalData = await fetchAllPickOrderLotsHierarchical(userIdToUse);
    console.log(" Hierarchical data (new structure):", hierarchicalData);
    
    //  检查数据结构
    if (!hierarchicalData.fgInfo || !hierarchicalData.pickOrders || hierarchicalData.pickOrders.length === 0) {
      console.warn("⚠️ No FG info or pick orders found");
      setCombinedLotData([]);
      setOriginalCombinedData([]);
      setAllLotsCompleted(false);
      setIssuePickedQtyBySolId({});
      return;
    }
    
    //  使用合并后的 pick order 对象（现在只有一个对象，包含所有数据）
    const mergedPickOrder = hierarchicalData.pickOrders[0];
    
    //  设置 FG info 到 fgPickOrders（用于显示 FG 信息卡片）
   // 修改第 478-509 行的 fgOrder 构建逻辑：

   const fgOrder: FGPickOrderResponse = {
    doPickOrderId: hierarchicalData.fgInfo.doPickOrderId,
    ticketNo: hierarchicalData.fgInfo.ticketNo,
    storeId: hierarchicalData.fgInfo.storeId,
    shopCode: hierarchicalData.fgInfo.shopCode,
    shopName: hierarchicalData.fgInfo.shopName,
    truckLanceCode: hierarchicalData.fgInfo.truckLanceCode,
    DepartureTime: hierarchicalData.fgInfo.departureTime,
    shopAddress: "",
    pickOrderCode: mergedPickOrder.pickOrderCodes?.[0] || "",
  
    // 兼容字段（注意 consoCodes 是数组）
    pickOrderId: mergedPickOrder.pickOrderIds?.[0] || 0,
    pickOrderConsoCode: Array.isArray(mergedPickOrder.consoCodes)
      ? mergedPickOrder.consoCodes[0] || ""
      : "",
    pickOrderTargetDate: mergedPickOrder.targetDate || "",
    pickOrderStatus: mergedPickOrder.status || "",
    deliveryOrderId: mergedPickOrder.doOrderIds?.[0] || 0,
    deliveryNo: mergedPickOrder.deliveryOrderCodes?.[0] || "",
    deliveryDate: "",
    shopId: 0,
    shopPoNo: "",
    numberOfCartons: mergedPickOrder.pickOrderLines?.length || 0,
    qrCodeData: hierarchicalData.fgInfo.doPickOrderId,
  
    // 多个 pick orders 信息：全部保留为数组
    numberOfPickOrders: mergedPickOrder.pickOrderIds?.length || 0,
    pickOrderIds: mergedPickOrder.pickOrderIds || [],
    pickOrderCodes: Array.isArray(mergedPickOrder.pickOrderCodes)
      ? mergedPickOrder.pickOrderCodes
      : [],
    deliveryOrderIds: mergedPickOrder.doOrderIds || [],
    deliveryNos: Array.isArray(mergedPickOrder.deliveryOrderCodes)
      ? mergedPickOrder.deliveryOrderCodes
      : [],
    lineCountsPerPickOrder: Array.isArray(mergedPickOrder.lineCountsPerPickOrder)
      ? mergedPickOrder.lineCountsPerPickOrder
      : [],
  };
  
  setFgPickOrders([fgOrder]);
  console.log("  DEBUG fgOrder.lineCountsPerPickOrder:", fgOrder.lineCountsPerPickOrder);
  console.log("  DEBUG fgOrder.pickOrderCodes:", fgOrder.pickOrderCodes);
  console.log("  DEBUG fgOrder.deliveryNos:", fgOrder.deliveryNos);
  
  // 直接使用合并后的 pickOrderLines
  console.log("🎯 Displaying merged pick order lines");
  
  // 将层级数据转换为平铺格式（用于表格显示）
  const flatLotData: any[] = [];

  // 2/F 與後端 store_id 一致時需按 itemOrder；避免 API 未走 2F 分支時畫面仍亂序
  const doFloorKey = String(hierarchicalData.fgInfo.storeId ?? '')
    .trim()
    .toUpperCase()
    .replace(/\//g, '')
    .replace(/\s/g, '');
  const pickOrderLinesForDisplay =
    doFloorKey === '2F'
      ? [...(mergedPickOrder.pickOrderLines || [])].sort((a: any, b: any) => {
          const ao = a.itemOrder != null ? Number(a.itemOrder) : 999999;
          const bo = b.itemOrder != null ? Number(b.itemOrder) : 999999;
          if (ao !== bo) return ao - bo;
          return (Number(a.id) || 0) - (Number(b.id) || 0);
        })
      : mergedPickOrder.pickOrderLines || [];

  pickOrderLinesForDisplay.forEach((line: any) => {
    // 用来记录这一行已经通过 lots 出现过的 lotId
    const lotIdSet = new Set<number>();
    /** 已由有批次建議分配的量（加總後與 pick_order_line.requiredQty 的差額 = 無批次列應顯示的數） */
    let lotsAllocatedSumForLine = 0;

    // ✅ lots：按 lotId 去重并合并 requiredQty
    if (line.lots && line.lots.length > 0) {
      const lotMap = new Map<number, any>();
  
      line.lots.forEach((lot: any) => {
        const lotId = lot.id;
        if (lotMap.has(lotId)) {
          const existingLot = lotMap.get(lotId);
          existingLot.requiredQty =
            (existingLot.requiredQty || 0) + (lot.requiredQty || 0);
        } else {
          lotMap.set(lotId, { ...lot });
        }
      });
  
      lotMap.forEach((lot: any) => {
        lotsAllocatedSumForLine += Number(lot.requiredQty) || 0;
        if (lot.id != null) {
          lotIdSet.add(lot.id);
        }
  
        flatLotData.push({
          pickOrderConsoCode: Array.isArray(mergedPickOrder.consoCodes)
            ? mergedPickOrder.consoCodes[0] || ""
            : "",
          pickOrderTargetDate: mergedPickOrder.targetDate,
          pickOrderStatus: mergedPickOrder.status,
          pickOrderId: line.pickOrderId || mergedPickOrder.pickOrderIds?.[0] || 0,
          pickOrderCode: mergedPickOrder.pickOrderCodes?.[0] || "",
          pickOrderLineId: line.id,
          pickOrderLineRequiredQty: line.requiredQty,
          pickOrderLineStatus: line.status,
  
          itemId: line.item.id,
          itemCode: line.item.code,
          itemName: line.item.name,
          uomDesc: line.item.uomDesc,
          uomShortDesc: line.item.uomShortDesc,
  
          lotId: lot.id,
          lotNo: lot.lotNo,
          expiryDate: lot.expiryDate,
          location: lot.location,
          stockUnit: lot.stockUnit,
          availableQty: lot.availableQty,
          requiredQty: lot.requiredQty,
          actualPickQty: lot.actualPickQty,
          inQty: lot.inQty,
          outQty: lot.outQty,
          holdQty: lot.holdQty,
          lotStatus: lot.lotStatus,
          lotAvailability: lot.lotAvailability,
          processingStatus: lot.processingStatus,
          suggestedPickLotId: lot.suggestedPickLotId,
          stockOutLineId: lot.stockOutLineId,
          stockOutLineStatus: lot.stockOutLineStatus,
          stockOutLineQty: lot.stockOutLineQty,
          stockInLineId: lot.stockInLineId,
          routerId: lot.router?.id,
          routerIndex: lot.router?.index,
          routerRoute: lot.router?.route,
          routerArea: lot.router?.area,
          noLot: false,
        });
      });
    }
  
    // ✅ stockouts：只保留“真正无批次 / 未在 lots 出现过”的行
    if (line.stockouts && line.stockouts.length > 0) {
      line.stockouts.forEach((stockout: any) => {
        const hasLot = stockout.lotId != null;
        const lotAlreadyInLots =
          hasLot && lotIdSet.has(stockout.lotId as number);
  
        // 有批次 & 已经通过 lots 渲染过 → 跳过，避免一条变两行
        if (!stockout.noLot && lotAlreadyInLots) {
          return;
        }
  
        // 只渲染：
        // - noLot === true 的 Null stock 行
        // - 或者 lotId 在 lots 中不存在的特殊情况
        flatLotData.push({
          pickOrderConsoCode: Array.isArray(mergedPickOrder.consoCodes)
            ? mergedPickOrder.consoCodes[0] || ""
            : "",
          pickOrderTargetDate: mergedPickOrder.targetDate,
          pickOrderStatus: mergedPickOrder.status,
          pickOrderId: line.pickOrderId || mergedPickOrder.pickOrderIds?.[0] || 0,
          pickOrderCode: mergedPickOrder.pickOrderCodes?.[0] || "",
          pickOrderLineId: line.id,
          pickOrderLineRequiredQty: line.requiredQty,
          pickOrderLineStatus: line.status,
  
          itemId: line.item.id,
          itemCode: line.item.code,
          itemName: line.item.name,
          uomDesc: line.item.uomDesc,
          uomShortDesc: line.item.uomShortDesc,
  
          lotId: stockout.lotId || null,
          lotNo: stockout.lotNo || null,
          expiryDate: null,
          location: stockout.location || null,
          stockUnit: line.item.uomDesc,
          availableQty: stockout.availableQty || 0,
          // 無批次列對應 suggested_pick_lot 的缺口量（如 11），勿用整行 POL 需求（100）以免顯示成 89 / 100
          requiredQty: stockout.noLot
            ? Math.max(
                0,
                (Number(line.requiredQty) || 0) - lotsAllocatedSumForLine
              )
            : Number(line.requiredQty) || 0,
          actualPickQty: stockout.qty || 0,
          inQty: 0,
          outQty: 0,
          holdQty: 0,
          lotStatus: stockout.noLot ? "unavailable" : "available",
          lotAvailability: stockout.noLot ? "insufficient_stock" : "available",
          processingStatus: stockout.status || "pending",
          suggestedPickLotId: null,
          stockOutLineId: stockout.id || null,
          stockOutLineStatus: stockout.status || null,
          stockOutLineQty: stockout.qty || 0,
  
          routerId: null,
          routerIndex: stockout.noLot ? 999999 : null,
          routerRoute: null,
          routerArea: null,
          noLot: !!stockout.noLot,
        });
      });
    }
  });
  
  console.log(" Transformed flat lot data:", flatLotData);
  console.log("  Total items (including null stock):", flatLotData.length);
  
  setCombinedLotData(flatLotData);
  setOriginalCombinedData(flatLotData);
  const doPid = hierarchicalData.fgInfo?.doPickOrderId;
  if (doPid) {
    setIssuePickedQtyBySolId(loadIssuePickedMap(doPid));
  }
  checkAllLotsCompleted(flatLotData);
  } catch (error) {
    console.error("  Error fetching combined lot data:", error);
    setCombinedLotData([]);
    setOriginalCombinedData([]);
    setAllLotsCompleted(false);
    setIssuePickedQtyBySolId({});
  } finally {
    setCombinedDataLoading(false);
  }
}, [currentUserId, checkAllLotsCompleted]); //   移除 selectedPickOrderId 依赖
  //  Add effect to check completion when lot data changes
  const handleManualLotConfirmation = useCallback(async (currentLotNo: string, newLotNo: string) => {
    console.log(`  Manual lot confirmation: Current=${currentLotNo}, New=${newLotNo}`);
    
    // 使用第一个输入框的 lot number 查找当前数据
    const currentLot = combinedLotData.find(lot => 
      lot.lotNo && lot.lotNo === currentLotNo
    );
    
    if (!currentLot) {
      console.error(`❌ Current lot not found: ${currentLotNo}`);
      alert(t("Current lot number not found. Please verify and try again."));
      return;
    }
    
    if (!currentLot.stockOutLineId) {
      console.error("❌ No stockOutLineId found for current lot");
      alert(t("No stock out line found for current lot. Please contact administrator."));
      return;
    }
    
    setIsConfirmingLot(true);
    
    try {
      // 调用 updateStockOutLineStatusByQRCodeAndLotNo API
      // 第一个 lot 用于获取 pickOrderLineId, stockOutLineId, itemId
      // 第二个 lot 作为 inventoryLotNo
      const res = await updateStockOutLineStatusByQRCodeAndLotNo({
        pickOrderLineId: currentLot.pickOrderLineId,
        inventoryLotNo: newLotNo, // 第二个输入框的值
        stockOutLineId: currentLot.stockOutLineId,
        itemId: currentLot.itemId,
        status: "checked",
      });
      
      console.log("📥 updateStockOutLineStatusByQRCodeAndLotNo result:", res);
      
      if (res.code === "checked" || res.code === "SUCCESS") {
        // ✅ 更新本地状态
        const entity = res.entity as any;
        
        setCombinedLotData(prev => prev.map(lot => {
          if (lot.stockOutLineId === currentLot.stockOutLineId &&
              lot.pickOrderLineId === currentLot.pickOrderLineId) {
            return {
              ...lot,
              stockOutLineStatus: 'checked',
              stockOutLineQty: entity?.qty ? Number(entity.qty) : lot.stockOutLineQty,
            };
          }
          return lot;
        }));
    
        setOriginalCombinedData(prev => prev.map(lot => {
          if (lot.stockOutLineId === currentLot.stockOutLineId &&
              lot.pickOrderLineId === currentLot.pickOrderLineId) {
            return {
              ...lot,
              stockOutLineStatus: 'checked',
              stockOutLineQty: entity?.qty ? Number(entity.qty) : lot.stockOutLineQty,
            };
          }
          return lot;
        }));
        
        console.log("✅ Lot substitution completed successfully");
        setQrScanSuccess(true);
        setQrScanError(false);
        
        // 关闭手动输入模态框
        setManualLotConfirmationOpen(false);
        
        // 刷新数据
        await fetchAllCombinedLotData();
      } else if (res.code === "LOT_NUMBER_MISMATCH") {
        console.warn("⚠️ Backend reported LOT_NUMBER_MISMATCH:", res.message);
        
        // ✅ 打开 lot confirmation modal 而不是显示 alert
        // 从响应消息中提取 expected lot number（如果可能）
        // 或者使用 currentLotNo 作为 expected lot
        const expectedLotNo = currentLotNo; // 当前 lot 是期望的
        
        // 查找新 lot 的信息（如果存在于 combinedLotData 中）
        const newLot = combinedLotData.find(lot => 
          lot.lotNo && lot.lotNo === newLotNo
        );
        
        // 设置 expected lot data
        setExpectedLotData({
          lotNo: expectedLotNo,
          itemCode: currentLot.itemCode || '',
          itemName: currentLot.itemName || ''
        });
        
        // 设置 scanned lot data
        setScannedLotData({
          lotNo: newLotNo,
          itemCode: newLot?.itemCode || currentLot.itemCode || '',
          itemName: newLot?.itemName || currentLot.itemName || '',
          inventoryLotLineId: newLot?.lotId || null,
          stockInLineId: null // 手动输入时可能没有 stockInLineId
        });
        
        // 设置 selectedLotForQr 为当前 lot
        setSelectedLotForQr(currentLot);
        
        // 关闭手动输入模态框
        setManualLotConfirmationOpen(false);
        
        // 打开 lot confirmation modal
        setLotConfirmationOpen(true);
        
        setQrScanError(false); // 不显示错误，因为会打开确认模态框
        setQrScanSuccess(false);
      } else if (res.code === "ITEM_MISMATCH") {
        console.warn("⚠️ Backend reported ITEM_MISMATCH:", res.message);
        alert(t("Item mismatch: {message}", { message: res.message || "" }));
        setQrScanError(true);
        setQrScanSuccess(false);
        
        // 关闭手动输入模态框
        setManualLotConfirmationOpen(false);
      } else {
        console.warn("⚠️ Unexpected response code:", res.code);
        alert(t("Failed to update lot status. Response: {code}", { code: res.code }));
        setQrScanError(true);
        setQrScanSuccess(false);
        
        // 关闭手动输入模态框
        setManualLotConfirmationOpen(false);
      }
      
    } catch (error) {
      console.error("❌ Error in manual lot confirmation:", error);
      alert(t("Failed to confirm lot substitution. Please try again."));
      setQrScanError(true);
      setQrScanSuccess(false);
      
      // 关闭手动输入模态框
      setManualLotConfirmationOpen(false);
    } finally {
      setIsConfirmingLot(false);
    }
  }, [combinedLotData, fetchAllCombinedLotData, t]);
  useEffect(() => {
    if (combinedLotData.length > 0) {
      checkAllLotsCompleted(combinedLotData);
    }
  }, [combinedLotData, checkAllLotsCompleted]);

  //  Add function to expose completion status to parent
  const getCompletionStatus = useCallback(() => {
    return allLotsCompleted;
  }, [allLotsCompleted]);

  //  Expose completion status to parent component
  useEffect(() => {
    // Dispatch custom event with completion status
    const event = new CustomEvent('pickOrderCompletionStatus', {
      detail: { 
        allLotsCompleted,
        tabIndex: 1 //  明确指定这是来自标签页 1 的事件
      }
    });
    window.dispatchEvent(event);
  }, [allLotsCompleted]);

  const clearLotConfirmationState = useCallback((clearProcessedRefs: boolean = false) => {
    setLotConfirmationOpen(false);
    setLotConfirmationError(null);
    setExpectedLotData(null);
    setScannedLotData(null);
    setSelectedLotForQr(null);
    lotConfirmLastQrRef.current = '';
    lotConfirmSkipNextScanRef.current = false;
    lotConfirmOpenedAtRef.current = 0;

    if (clearProcessedRefs) {
      setTimeout(() => {
        lastProcessedQrRef.current = '';
        processedQrCodesRef.current.clear();
        console.log(`  [LOT CONFIRM MODAL] Cleared refs to allow reprocessing`);
      }, 100);
    }
  }, []);

  const parseQrPayload = useCallback((rawQr: string): { itemId: number; stockInLineId: number } | null => {
    if (!rawQr) return null;

    if ((rawQr.startsWith("{2fitest") || rawQr.startsWith("{2fittest")) && rawQr.endsWith("}")) {
      let content = '';
      if (rawQr.startsWith("{2fittest")) {
        content = rawQr.substring(9, rawQr.length - 1);
      } else {
        content = rawQr.substring(8, rawQr.length - 1);
      }

      const parts = content.split(',');
      if (parts.length === 2) {
        const itemId = parseInt(parts[0].trim(), 10);
        const stockInLineId = parseInt(parts[1].trim(), 10);
        if (!isNaN(itemId) && !isNaN(stockInLineId)) {
          return { itemId, stockInLineId };
        }
      }
      return null;
    }

    try {
      const parsed = JSON.parse(rawQr);
      if (parsed?.itemId && parsed?.stockInLineId) {
        return { itemId: parsed.itemId, stockInLineId: parsed.stockInLineId };
      }
      return null;
    } catch {
      return null;
    }
  }, []);

  const handleLotConfirmation = useCallback(async (overrideScannedLot?: any) => {
    const effectiveScannedLot = overrideScannedLot ?? scannedLotData;
    if (!expectedLotData || !effectiveScannedLot || !selectedLotForQr) return;
    setIsConfirmingLot(true);
    setLotConfirmationError(null);
    try {
      const newLotNo = effectiveScannedLot?.lotNo;
  
      const newStockInLineId = effectiveScannedLot?.stockInLineId;
    
      const substitutionResult = await confirmLotSubstitution({
        pickOrderLineId: selectedLotForQr.pickOrderLineId,
        stockOutLineId: selectedLotForQr.stockOutLineId,
        originalSuggestedPickLotId: selectedLotForQr.suggestedPickLotId,
        newInventoryLotNo: "",             
        newStockInLineId: newStockInLineId    
      });

      const substitutionCode = substitutionResult?.code;
      const switchedToUnavailable =
        substitutionCode === "SUCCESS_UNAVAILABLE" || substitutionCode === "BOUND_UNAVAILABLE";
      if (!substitutionResult || (substitutionCode !== "SUCCESS" && !switchedToUnavailable)) {
        const errMsg =
          substitutionResult?.code === "LOT_UNAVAILABLE"
            ? t(
                "The scanned lot inventory line is unavailable. Cannot switch or bind; pick line was not updated."
              )
            : substitutionResult?.message ||
              t("Lot switch failed; pick line was not marked as checked.");
        setLotConfirmationError(errMsg);
        setQrScanError(true);
        setQrScanSuccess(false);
        setQrScanErrorMsg(errMsg);
        return;
      }
  
      setQrScanError(false);
      setQrScanSuccess(false);
      setQrScanInput('');
      
      // ✅ 修复：在确认后重置扫描状态，避免重复处理
      resetScan();
      
      // ✅ 修复：不要清空 processedQrCodes，而是保留当前 QR code 的标记
      // 或者如果确实需要清空，应该在重置扫描后再清空
      // setProcessedQrCodes(new Set());
      // setLastProcessedQr('');
      
      setPickExecutionFormOpen(false);
      if (selectedLotForQr?.stockOutLineId && !switchedToUnavailable) {
        const stockOutLineUpdate = await updateStockOutLineStatus({
          id: selectedLotForQr.stockOutLineId,
          status: 'checked',
          qty: 0
        });
      }
      
      // ✅ 修复：先关闭 modal 和清空状态，再刷新数据
      clearLotConfirmationState(false);
      
      // ✅ 修复：刷新数据前设置刷新标志，避免在刷新期间处理新的 QR code
      setIsRefreshingData(true);
      await fetchAllCombinedLotData();
      setIsRefreshingData(false);
    } catch (error) {
      console.error("Error confirming lot substitution:", error);
      const errMsg = t("Lot confirmation failed. Please try again.");
      setLotConfirmationError(errMsg);
      setQrScanError(true);
      setQrScanErrorMsg(errMsg);
    } finally {
      setIsConfirmingLot(false);
    }
  }, [expectedLotData, scannedLotData, selectedLotForQr, fetchAllCombinedLotData, resetScan, clearLotConfirmationState, t]);

  const handleLotConfirmationByRescan = useCallback(async (rawQr: string): Promise<boolean> => {
    if (!lotConfirmationOpen || !selectedLotForQr || !expectedLotData || !scannedLotData) {
      return false;
    }

    const payload = parseQrPayload(rawQr);
    const expectedStockInLineId = Number(selectedLotForQr.stockInLineId);
    const mismatchedStockInLineId = Number(scannedLotData?.stockInLineId);

    if (payload) {
      const rescannedStockInLineId = Number(payload.stockInLineId);

      // 再扫“差异 lot” => 直接执行切换
      if (
        Number.isFinite(mismatchedStockInLineId) &&
        rescannedStockInLineId === mismatchedStockInLineId
      ) {
        await handleLotConfirmation();
        return true;
      }

      // 再扫“原建议 lot” => 关闭弹窗并按原 lot 正常记一次扫描
      if (
        Number.isFinite(expectedStockInLineId) &&
        rescannedStockInLineId === expectedStockInLineId
      ) {
        clearLotConfirmationState(false);
        if (processOutsideQrCodeRef.current) {
          await processOutsideQrCodeRef.current(JSON.stringify(payload));
        }
        return true;
      }

      // 扫到第三个 lot（既不是当前差异 lot，也不是原建议 lot）：
      // 直接按“扫描到的这一批”执行切换。
      await handleLotConfirmation({
        lotNo: null,
        itemCode: expectedLotData?.itemCode,
        itemName: expectedLotData?.itemName,
        inventoryLotLineId: null,
        stockInLineId: rescannedStockInLineId
      });
      return true;
    } else {
      // 兼容纯 lotNo 文本扫码
      const scannedText = rawQr?.trim();
      const expectedLotNo = expectedLotData?.lotNo?.trim();
      const mismatchedLotNo = scannedLotData?.lotNo?.trim();

      if (mismatchedLotNo && scannedText === mismatchedLotNo) {
        await handleLotConfirmation();
        return true;
      }

      if (expectedLotNo && scannedText === expectedLotNo) {
        clearLotConfirmationState(false);
        if (processOutsideQrCodeRef.current) {
          await processOutsideQrCodeRef.current(JSON.stringify({
            itemId: selectedLotForQr.itemId,
            stockInLineId: selectedLotForQr.stockInLineId,
          }));
        }
        return true;
      }
    }

    return false;
  }, [lotConfirmationOpen, selectedLotForQr, expectedLotData, scannedLotData, parseQrPayload, handleLotConfirmation, clearLotConfirmationState, handleLotMismatch]);

  const handleQrCodeSubmit = useCallback(async (lotNo: string) => {
    console.log(` Processing QR Code for lot: ${lotNo}`);
    
    //  检查 lotNo 是否为 null 或 undefined（包括字符串 "null"）
    if (!lotNo || lotNo === 'null' || lotNo.trim() === '') {
      console.error("  Invalid lotNo: null, undefined, or empty");
      return;
    }
    
    //  Use current data without refreshing to avoid infinite loop
    const currentLotData = combinedLotData;
    console.log(` Available lots:`, currentLotData.map(lot => lot.lotNo));
    
    //  修复：在比较前确保 lotNo 不为 null
    const lotNoLower = lotNo.toLowerCase();
    const matchingLots = currentLotData.filter(lot => {
      if (!lot.lotNo) return false; //  跳过 null lotNo
      return lot.lotNo === lotNo || lot.lotNo.toLowerCase() === lotNoLower;
    });
    
    if (matchingLots.length === 0) {
      console.error(`  Lot not found: ${lotNo}`);
      setQrScanError(true);
      setQrScanSuccess(false);
      const availableLotNos = currentLotData.map(lot => lot.lotNo).join(', ');
      console.log(`  QR Code "${lotNo}" does not match any expected lots. Available lots: ${availableLotNos}`);
      return; 
    }

    const hasExpiredLot = matchingLots.some(
      (lot: any) => String(lot.lotAvailability || '').toLowerCase() === 'expired'
    );
    if (hasExpiredLot) {
      console.warn(`⚠️ [QR PROCESS] Scanned lot ${lotNo} is expired`);
      setQrScanError(true);
      setQrScanSuccess(false);
      return;
    }
    
    console.log(` Found ${matchingLots.length} matching lots:`, matchingLots);
    setQrScanError(false);
    
    try {
      let successCount = 0;
      let errorCount = 0;
      
      for (const matchingLot of matchingLots) {
        console.log(`🔄 Processing pick order line ${matchingLot.pickOrderLineId} for lot ${lotNo}`);
        
        if (matchingLot.stockOutLineId) {
          const stockOutLineUpdate = await updateStockOutLineStatus({
            id: matchingLot.stockOutLineId,
            status: 'checked',
            qty: 0
          });
          console.log(`Update stock out line result for line ${matchingLot.pickOrderLineId}:`, stockOutLineUpdate);

          // Treat multiple backend shapes as success (type-safe via any)
          const r: any = stockOutLineUpdate as any;
          const updateOk =
            r?.code === 'SUCCESS' ||
            typeof r?.id === 'number' ||
            r?.type === 'checked' ||
            r?.status === 'checked' ||
            typeof r?.entity?.id === 'number' ||
            r?.entity?.status === 'checked';

          if (updateOk) {
            successCount++;
          } else {
            errorCount++;
          }
        } else {
          const createStockOutLineData = {
            consoCode: matchingLot.pickOrderConsoCode,
            pickOrderLineId: matchingLot.pickOrderLineId,
            inventoryLotLineId: matchingLot.lotId,
            qty: 0
          };
          
          const createResult = await createStockOutLine(createStockOutLineData);
          console.log(`Create stock out line result for line ${matchingLot.pickOrderLineId}:`, createResult);
          
          if (createResult && createResult.code === "SUCCESS") {
            // Immediately set status to checked for new line
            let newSolId: number | undefined;
            const anyRes: any = createResult as any;
            if (typeof anyRes?.id === 'number') {
              newSolId = anyRes.id;
            } else if (anyRes?.entity) {
              newSolId = Array.isArray(anyRes.entity) ? anyRes.entity[0]?.id : anyRes.entity?.id;
            }

            if (newSolId) {
              const setChecked = await updateStockOutLineStatus({
                id: newSolId,
                status: 'checked',
                qty: 0
              });
              if (setChecked && setChecked.code === "SUCCESS") {
                successCount++;
              } else {
                errorCount++;
              }
            } else {
              console.warn("Created stock out line but no ID returned; cannot set to checked");
              errorCount++;
            }
          } else {
            errorCount++;
          }
        }
      }
      
      //  FIXED: Set refresh flag before refreshing data
      setIsRefreshingData(true);
      console.log("🔄 Refreshing data after QR code processing...");
      await fetchAllCombinedLotData();
      
      if (successCount > 0) {
        console.log(` QR Code processing completed: ${successCount} updated/created`);
        setQrScanSuccess(true);
        setQrScanError(false);
        setQrScanInput(''); // Clear input after successful processing
        //setIsManualScanning(false);
       // stopScan();
       // resetScan();
        //  Clear success state after a delay
        
        //setTimeout(() => {
          //setQrScanSuccess(false);
        //}, 2000);
      } else {
        console.error(`  QR Code processing failed: ${errorCount} errors`);
        setQrScanError(true);
        setQrScanSuccess(false);
        
        //  Clear error state after a delay
       // setTimeout(() => {
         // setQrScanError(false);
        //}, 3000);
      }
    } catch (error) {
      console.error("  Error processing QR code:", error);
      setQrScanError(true);
      setQrScanSuccess(false);
      
    
      //  Clear error state after a delay
      setTimeout(() => {
        setQrScanError(false);
      }, 3000);
    } finally {
      //  Clear refresh flag after a short delay
      setTimeout(() => {
        setIsRefreshingData(false);
      }, 1000);
    }
  }, [combinedLotData]);
  const handleFastQrScan = useCallback(async (lotNo: string) => {
    const startTime = performance.now();
    console.log(`  [FAST SCAN START] Lot: ${lotNo}`);
    console.log(`  Start time: ${new Date().toISOString()}`);
    
    // 从 combinedLotData 中找到对应的 lot
    const findStartTime = performance.now();
    const matchingLot = combinedLotData.find(lot => 
      lot.lotNo && lot.lotNo === lotNo
    );
    const findTime = performance.now() - findStartTime;
    console.log(`  Find lot time: ${findTime.toFixed(2)}ms`);
  
    if (!matchingLot || !matchingLot.stockOutLineId) {
      const totalTime = performance.now() - startTime;
      console.warn(`⚠️ Fast scan: Lot ${lotNo} not found or no stockOutLineId`);
      console.log(`  Total time: ${totalTime.toFixed(2)}ms`);
      return;
    }
  
    try {
      // ✅ 使用快速 API
      const apiStartTime = performance.now();
      const res = await updateStockOutLineStatusByQRCodeAndLotNo({
        pickOrderLineId: matchingLot.pickOrderLineId,
        inventoryLotNo: lotNo,
        stockOutLineId: matchingLot.stockOutLineId,
        itemId: matchingLot.itemId,
        status: "checked",
      });
      const apiTime = performance.now() - apiStartTime;
      console.log(`  API call time: ${apiTime.toFixed(2)}ms`);
  
      if (res.code === "checked" || res.code === "SUCCESS") {
        // ✅ 只更新本地状态，不调用 fetchAllCombinedLotData
        const updateStartTime = performance.now();
        const entity = res.entity as any;
        
        setCombinedLotData(prev => prev.map(lot => {
          if (lot.stockOutLineId === matchingLot.stockOutLineId &&
              lot.pickOrderLineId === matchingLot.pickOrderLineId) {
            return {
              ...lot,
              stockOutLineStatus: 'checked',
              stockOutLineQty: entity?.qty ? Number(entity.qty) : lot.stockOutLineQty,
            };
          }
          return lot;
        }));
  
        setOriginalCombinedData(prev => prev.map(lot => {
          if (lot.stockOutLineId === matchingLot.stockOutLineId &&
              lot.pickOrderLineId === matchingLot.pickOrderLineId) {
            return {
              ...lot,
              stockOutLineStatus: 'checked',
              stockOutLineQty: entity?.qty ? Number(entity.qty) : lot.stockOutLineQty,
            };
          }
          return lot;
        }));
        const updateTime = performance.now() - updateStartTime;
        console.log(`  State update time: ${updateTime.toFixed(2)}ms`);
  
        const totalTime = performance.now() - startTime;
        console.log(`✅ [FAST SCAN END] Lot: ${lotNo}`);
        console.log(`  Total time: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`);
        console.log(`  End time: ${new Date().toISOString()}`);
      } else {
        const totalTime = performance.now() - startTime;
        console.warn(`⚠️ Fast scan failed for ${lotNo}:`, res.code);
        console.log(`  Total time: ${totalTime.toFixed(2)}ms`);
      }
    } catch (error) {
      const totalTime = performance.now() - startTime;
      console.error(`  Fast scan error for ${lotNo}:`, error);
      console.log(`  Total time: ${totalTime.toFixed(2)}ms`);
    }
  }, [combinedLotData, updateStockOutLineStatusByQRCodeAndLotNo]);
  // Enhanced lotDataIndexes with cached active lots for better performance
  const lotDataIndexes = useMemo(() => {
    const indexStartTime = performance.now();
    console.log(`  [PERF] lotDataIndexes calculation START, data length: ${combinedLotData.length}`);
    
    const byItemId = new Map<number, any[]>();
    const byItemCode = new Map<string, any[]>();
    const byLotId = new Map<number, any>();
    const byLotNo = new Map<string, any[]>();
    const byStockInLineId = new Map<number, any[]>();
    // Cache active lots separately to avoid filtering on every scan
    const activeLotsByItemId = new Map<number, any[]>();
    const rejectedStatuses = new Set(['rejected']);
    
    // ✅ Use for loop instead of forEach for better performance on tablets
    for (let i = 0; i < combinedLotData.length; i++) {
      const lot = combinedLotData[i];
      const solStatus = String(lot.stockOutLineStatus || "").toLowerCase();
      const lotAvailability = String(lot.lotAvailability || "").toLowerCase();
      const processingStatus = String(lot.processingStatus || "").toLowerCase();
      const isUnavailable = isInventoryLotLineUnavailable(lot);
      const isExpired = isLotAvailabilityExpired(lot);
      const isRejected =
        rejectedStatuses.has(lotAvailability) ||
        rejectedStatuses.has(solStatus) ||
        rejectedStatuses.has(processingStatus);
      const isEnded = solStatus === "checked" || solStatus === "completed";
      const isPartially = solStatus === "partially_completed" || solStatus === "partially_complete";
      const isPending = solStatus === "pending" || solStatus === "";
      const isActive = !isRejected && !isUnavailable && !isExpired && !isEnded && (isPending || isPartially);
      
      if (lot.itemId) {
        if (!byItemId.has(lot.itemId)) {
          byItemId.set(lot.itemId, []);
          activeLotsByItemId.set(lot.itemId, []);
        }
        byItemId.get(lot.itemId)!.push(lot);
        if (isActive) {
          activeLotsByItemId.get(lot.itemId)!.push(lot);
        }
      }
      
      if (lot.itemCode) {
        if (!byItemCode.has(lot.itemCode)) {
          byItemCode.set(lot.itemCode, []);
        }
        byItemCode.get(lot.itemCode)!.push(lot);
      }
      
      if (lot.lotId) {
        byLotId.set(lot.lotId, lot);
      }
      
      if (lot.lotNo) {
        if (!byLotNo.has(lot.lotNo)) {
          byLotNo.set(lot.lotNo, []);
        }
        byLotNo.get(lot.lotNo)!.push(lot);
      }
      
      if (lot.stockInLineId) {
        if (!byStockInLineId.has(lot.stockInLineId)) {
          byStockInLineId.set(lot.stockInLineId, []);
        }
        byStockInLineId.get(lot.stockInLineId)!.push(lot);
      }
    }
    
    const indexTime = performance.now() - indexStartTime;
    if (indexTime > 10) {
      console.log(`  [PERF] lotDataIndexes calculation END: ${indexTime.toFixed(2)}ms (${(indexTime / 1000).toFixed(3)}s)`);
    }
    
    return { byItemId, byItemCode, byLotId, byLotNo, byStockInLineId, activeLotsByItemId };
  }, [combinedLotData.length, combinedLotData]);
  
  // Store resetScan in ref for immediate access (update on every render)
  resetScanRef.current = resetScan;
  
  const processOutsideQrCode = useCallback(async (latestQr: string, qrScanCountAtInvoke?: number) => {
    const totalStartTime = performance.now();
    console.log(`  [PROCESS OUTSIDE QR START] QR: ${latestQr.substring(0, 50)}...`);
    console.log(`  Start time: ${new Date().toISOString()}`);
    
    // ✅ Measure index access time
    const indexAccessStart = performance.now();
    const indexes = lotDataIndexes; // Access the memoized indexes
    const indexAccessTime = performance.now() - indexAccessStart;
    console.log(`  [PERF] Index access time: ${indexAccessTime.toFixed(2)}ms`);
    
    // 1) Parse JSON safely (parse once, reuse)
    const parseStartTime = performance.now();
    let qrData: any = null;
    let parseTime = 0;
    try {
      qrData = JSON.parse(latestQr);
      parseTime = performance.now() - parseStartTime;
      console.log(`  [PERF] JSON parse time: ${parseTime.toFixed(2)}ms`);
    } catch {
      console.log("QR content is not JSON; skipping lotNo direct submit to avoid false matches.");
      startTransition(() => {
        setQrScanError(true);
        setQrScanSuccess(false);
      });
      return;
    }
  
    try {
      const validationStartTime = performance.now();
      if (!(qrData?.stockInLineId && qrData?.itemId)) {
        console.log("QR JSON missing required fields (itemId, stockInLineId).");
        startTransition(() => {
          setQrScanError(true);
          setQrScanSuccess(false);
        });
        return;
      }
      const validationTime = performance.now() - validationStartTime;
      console.log(`  [PERF] Validation time: ${validationTime.toFixed(2)}ms`);
  
      const scannedItemId = qrData.itemId;
      const scannedStockInLineId = qrData.stockInLineId;
      
      // ✅ Check if this combination was already processed
      const duplicateCheckStartTime = performance.now();
      const itemProcessedSet = processedQrCombinations.get(scannedItemId);
      if (itemProcessedSet?.has(scannedStockInLineId)) {
        const duplicateCheckTime = performance.now() - duplicateCheckStartTime;
        console.log(`  [SKIP] Already processed combination: itemId=${scannedItemId}, stockInLineId=${scannedStockInLineId} (check time: ${duplicateCheckTime.toFixed(2)}ms)`);
        return;
      }
      const duplicateCheckTime = performance.now() - duplicateCheckStartTime;
      console.log(`  [PERF] Duplicate check time: ${duplicateCheckTime.toFixed(2)}ms`);
      
      // ✅ OPTIMIZATION: Use cached active lots directly (no filtering needed)
      const lookupStartTime = performance.now();
      const activeSuggestedLots = indexes.activeLotsByItemId.get(scannedItemId) || [];
      // ✅ Also get all lots for this item (not just active ones) to allow lot switching even when all lots are rejected
      const allLotsForItem = indexes.byItemId.get(scannedItemId) || [];
      const lookupTime = performance.now() - lookupStartTime;
      console.log(`  [PERF] Index lookup time: ${lookupTime.toFixed(2)}ms, found ${activeSuggestedLots.length} active lots, ${allLotsForItem.length} total lots`);
      
      // ✅ Check if scanned lot is rejected BEFORE checking activeSuggestedLots
      // This allows users to scan other lots even when all suggested lots are rejected
      const scannedLot = allLotsForItem.find(
        (lot: any) => lot.stockInLineId === scannedStockInLineId
      );
      
      if (scannedLot) {
        const isRejected = 
          scannedLot.stockOutLineStatus?.toLowerCase() === 'rejected' ||
          scannedLot.lotAvailability === 'rejected' ||
          isInventoryLotLineUnavailable(scannedLot);
        
        if (isRejected) {
          console.warn(`⚠️ [QR PROCESS] Scanned lot (stockInLineId: ${scannedStockInLineId}, lotNo: ${scannedLot.lotNo}) is rejected or unavailable`);
          startTransition(() => {
            setQrScanError(true);
            setQrScanSuccess(false);
            setQrScanErrorMsg(
              `此批次（${scannedLot.lotNo || scannedStockInLineId}）已被拒绝，无法使用。请扫描其他批次。`
            );
          });
          // Mark as processed to prevent re-processing
          setProcessedQrCombinations(prev => {
            const newMap = new Map(prev);
            if (!newMap.has(scannedItemId)) newMap.set(scannedItemId, new Set());
            newMap.get(scannedItemId)!.add(scannedStockInLineId);
            return newMap;
          });
          return;
        }

        const isExpired =
          String(scannedLot.lotAvailability || '').toLowerCase() === 'expired';
        if (isExpired) {
          console.warn(`⚠️ [QR PROCESS] Scanned lot (stockInLineId: ${scannedStockInLineId}, lotNo: ${scannedLot.lotNo}) is expired`);
          startTransition(() => {
            setQrScanError(true);
            setQrScanSuccess(false);
            setQrScanErrorMsg(
              `此批次（${scannedLot.lotNo || scannedStockInLineId}）已过期，无法使用。请扫描其他批次。`
            );
          });
          // Mark as processed to prevent re-processing the same expired QR repeatedly
          setProcessedQrCombinations(prev => {
            const newMap = new Map(prev);
            if (!newMap.has(scannedItemId)) newMap.set(scannedItemId, new Set());
            newMap.get(scannedItemId)!.add(scannedStockInLineId);
            return newMap;
          });
          return;
        }
      }
      
      // ✅ If no active suggested lots, but scanned lot is not rejected, allow lot switching
      if (activeSuggestedLots.length === 0) {
        // Check if there are any lots for this item (even if all are rejected)
        if (allLotsForItem.length === 0) {
          console.error("No lots found for this item");
          startTransition(() => {
            setQrScanError(true);
            setQrScanSuccess(false);
            setQrScanErrorMsg("当前订单中没有此物品的批次信息");
          });
          return;
        }
        
        // ✅ Allow lot switching: find a rejected lot as expected lot, or use first lot
        // This allows users to switch to a new lot even when all suggested lots are rejected
        console.log(`⚠️ [QR PROCESS] No active suggested lots, but allowing lot switching.`);
        
        // Find a rejected lot as expected lot (the one that was rejected)
        const rejectedLot = allLotsForItem.find((lot: any) => 
          lot.stockOutLineStatus?.toLowerCase() === 'rejected' ||
          lot.lotAvailability === 'rejected' ||
          isInventoryLotLineUnavailable(lot)
        );
        const expectedLot =
          rejectedLot ||
          pickExpectedLotForSubstitution(
            allLotsForItem.filter(
              (l: any) => l.lotNo != null && String(l.lotNo).trim() !== ""
            )
          ) ||
          allLotsForItem[0];
        
        // ✅ Always open confirmation modal when no active lots (user needs to confirm switching)
        // handleLotMismatch will fetch lotNo from backend using stockInLineId if needed
        console.log(`⚠️ [QR PROCESS] Opening confirmation modal for lot switch (no active lots)`);
        setSelectedLotForQr(expectedLot);
        handleLotMismatch(
          {
            lotNo: expectedLot.lotNo,
            itemCode: expectedLot.itemCode,
            itemName: expectedLot.itemName
          },
          {
            lotNo: scannedLot?.lotNo || null, // Will be fetched by handleLotMismatch if null
            itemCode: expectedLot.itemCode,
            itemName: expectedLot.itemName,
            inventoryLotLineId: scannedLot?.lotId || null,
            stockInLineId: scannedStockInLineId // handleLotMismatch will use this to fetch lotNo
          },
          qrScanCountAtInvoke
        );
        return;
      }
      
      // ✅ OPTIMIZATION: Direct Map lookup for stockInLineId match (O(1))
      const matchStartTime = performance.now();
      let exactMatch: any = null;
      const stockInLineLots = indexes.byStockInLineId.get(scannedStockInLineId) || [];
      // Find exact match from stockInLineId index, then verify it's in active lots
      for (let i = 0; i < stockInLineLots.length; i++) {
        const lot = stockInLineLots[i];
        if (lot.itemId === scannedItemId && activeSuggestedLots.includes(lot)) {
          exactMatch = lot;
          break;
        }
      }
      const matchTime = performance.now() - matchStartTime;
      console.log(`  [PERF] Find exact match time: ${matchTime.toFixed(2)}ms, found: ${exactMatch ? 'yes' : 'no'}`);
      
      // ✅ Check if scanned lot exists in allLotsForItem but not in activeSuggestedLots
      // This handles the case where Lot A is rejected and user scans Lot B
      // Also handle case where scanned lot is not in allLotsForItem (scannedLot is undefined)
      if (!exactMatch) {
        // Scanned lot is not in active suggested lots, open confirmation modal
        const expectedLot =
          pickExpectedLotForSubstitution(activeSuggestedLots) || allLotsForItem[0];
        if (expectedLot) {
          // Check if scanned lot is different from expected, or if scannedLot is undefined (not in allLotsForItem)
          const shouldOpenModal = !scannedLot || (scannedLot.stockInLineId !== expectedLot.stockInLineId);
          if (shouldOpenModal) {
            console.log(`⚠️ [QR PROCESS] Opening confirmation modal (scanned lot ${scannedLot?.lotNo || 'not in data'} is not in active suggested lots)`);
            setSelectedLotForQr(expectedLot);
            handleLotMismatch(
              {
                lotNo: expectedLot.lotNo,
                itemCode: expectedLot.itemCode,
                itemName: expectedLot.itemName
              },
              {
                lotNo: scannedLot?.lotNo || null, // Will be fetched by handleLotMismatch if null
                itemCode: expectedLot.itemCode,
                itemName: expectedLot.itemName,
                inventoryLotLineId: scannedLot?.lotId || null,
                stockInLineId: scannedStockInLineId // handleLotMismatch will use this to fetch lotNo
              },
              qrScanCountAtInvoke
            );
            return;
          }
        }
      }
      
      if (exactMatch) {
        // ✅ Case 1: stockInLineId 匹配 - 直接处理，不需要确认
        console.log(`✅ Exact stockInLineId match found for lot: ${exactMatch.lotNo}`);
        
        if (!exactMatch.stockOutLineId) {
          console.warn("No stockOutLineId on exactMatch, cannot update status by QR.");
          startTransition(() => {
            setQrScanError(true);
            setQrScanSuccess(false);
          });
          return;
        }
  
        try {
          const apiStartTime = performance.now();
          console.log(`  [API CALL START] Calling updateStockOutLineStatusByQRCodeAndLotNo`);
          console.log(`  [API CALL] API start time: ${new Date().toISOString()}`);
          const res = await updateStockOutLineStatusByQRCodeAndLotNo({
            pickOrderLineId: exactMatch.pickOrderLineId,
            inventoryLotNo: exactMatch.lotNo,
            stockOutLineId: exactMatch.stockOutLineId,
            itemId: exactMatch.itemId,
            status: "checked",
          });
          const apiTime = performance.now() - apiStartTime;
          console.log(`  [API CALL END] Total API time: ${apiTime.toFixed(2)}ms (${(apiTime / 1000).toFixed(3)}s)`);
          console.log(`  [API CALL] API end time: ${new Date().toISOString()}`);
  
          if (res.code === "checked" || res.code === "SUCCESS") {
            const entity = res.entity as any;
            
            // ✅ Batch state updates using startTransition
            const stateUpdateStartTime = performance.now();
            startTransition(() => {
              setQrScanError(false);
              setQrScanSuccess(true);
              
              setCombinedLotData(prev => prev.map(lot => {
                if (lot.stockOutLineId === exactMatch.stockOutLineId &&
                    lot.pickOrderLineId === exactMatch.pickOrderLineId) {
                  return {
                    ...lot,
                    stockOutLineStatus: 'checked',
                    stockOutLineQty: entity?.qty ?? lot.stockOutLineQty,
                  };
                }
                return lot;
              }));
  
              setOriginalCombinedData(prev => prev.map(lot => {
                if (lot.stockOutLineId === exactMatch.stockOutLineId &&
                    lot.pickOrderLineId === exactMatch.pickOrderLineId) {
                  return {
                    ...lot,
                    stockOutLineStatus: 'checked',
                    stockOutLineQty: entity?.qty ?? lot.stockOutLineQty,
                  };
                }
                return lot;
              }));
            });
            const stateUpdateTime = performance.now() - stateUpdateStartTime;
            console.log(`  [PERF] State update time: ${stateUpdateTime.toFixed(2)}ms`);
            
            // Mark this combination as processed
            const markProcessedStartTime = performance.now();
            setProcessedQrCombinations(prev => {
              const newMap = new Map(prev);
              if (!newMap.has(scannedItemId)) {
                newMap.set(scannedItemId, new Set());
              }
              newMap.get(scannedItemId)!.add(scannedStockInLineId);
              return newMap;
            });
            const markProcessedTime = performance.now() - markProcessedStartTime;
            console.log(`  [PERF] Mark processed time: ${markProcessedTime.toFixed(2)}ms`);
  
            const totalTime = performance.now() - totalStartTime;
            console.log(`✅ [PROCESS OUTSIDE QR END] Total time: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`);
            console.log(`  End time: ${new Date().toISOString()}`);
            console.log(`📊 Breakdown: parse=${parseTime.toFixed(2)}ms, validation=${validationTime.toFixed(2)}ms, duplicateCheck=${duplicateCheckTime.toFixed(2)}ms, lookup=${lookupTime.toFixed(2)}ms, match=${matchTime.toFixed(2)}ms, api=${apiTime.toFixed(2)}ms, stateUpdate=${stateUpdateTime.toFixed(2)}ms, markProcessed=${markProcessedTime.toFixed(2)}ms`);
            console.log("✅ Status updated locally, no full data refresh needed");
          } else {
            console.warn("Unexpected response code from backend:", res.code);
            startTransition(() => {
              setQrScanError(true);
              setQrScanSuccess(false);
            });
          }
        } catch (e) {
          const totalTime = performance.now() - totalStartTime;
          console.error(`❌ [PROCESS OUTSIDE QR ERROR] Total time: ${totalTime.toFixed(2)}ms`);
          console.error("Error calling updateStockOutLineStatusByQRCodeAndLotNo:", e);
          startTransition(() => {
            setQrScanError(true);
            setQrScanSuccess(false);
          });
        }
  
        return; // ✅ 直接返回，不需要确认表单
      }
      
      // ✅ Case 2: itemId 匹配但 stockInLineId 不匹配 - 显示确认表单
      // Check if we should allow reopening (different stockInLineId)
      const mismatchCheckStartTime = performance.now();
      const itemProcessedSet2 = processedQrCombinations.get(scannedItemId);
      if (itemProcessedSet2?.has(scannedStockInLineId)) {
        const mismatchCheckTime = performance.now() - mismatchCheckStartTime;
        console.log(`  [SKIP] Already processed this exact combination (check time: ${mismatchCheckTime.toFixed(2)}ms)`);
        return;
      }
      const mismatchCheckTime = performance.now() - mismatchCheckStartTime;
      console.log(`  [PERF] Mismatch check time: ${mismatchCheckTime.toFixed(2)}ms`);
      
      // 取应被替换的活跃行（同物料多行时优先有建议批次的行）
      const expectedLotStartTime = performance.now();
      const expectedLot = pickExpectedLotForSubstitution(activeSuggestedLots);
      if (!expectedLot) {
        console.error("Could not determine expected lot for confirmation");
        startTransition(() => {
          setQrScanError(true);
          setQrScanSuccess(false);
        });
        return;
      }
      const expectedLotTime = performance.now() - expectedLotStartTime;
      console.log(`  [PERF] Get expected lot time: ${expectedLotTime.toFixed(2)}ms`);
      
      // ✅ 立即打开确认模态框，不等待其他操作
      console.log(`⚠️ Lot mismatch: Expected stockInLineId=${expectedLot.stockInLineId}, Scanned stockInLineId=${scannedStockInLineId}`);
      
      // Set selected lot immediately (no transition delay)
      const setSelectedLotStartTime = performance.now();
      setSelectedLotForQr(expectedLot);
      const setSelectedLotTime = performance.now() - setSelectedLotStartTime;
      console.log(`  [PERF] Set selected lot time: ${setSelectedLotTime.toFixed(2)}ms`);
      
      // ✅ 获取扫描的 lot 信息（从 QR 数据中提取，或使用默认值）
      // Call handleLotMismatch immediately - it will open the modal
      const handleMismatchStartTime = performance.now();
      handleLotMismatch(
        {
          lotNo: expectedLot.lotNo,
          itemCode: expectedLot.itemCode,
          itemName: expectedLot.itemName
        },
        {
          lotNo: null, // 扫描的 lotNo 未知，需要从后端获取或显示为未知
          itemCode: expectedLot.itemCode,
          itemName: expectedLot.itemName,
          inventoryLotLineId: null,
          stockInLineId: scannedStockInLineId // ✅ 传递 stockInLineId
        },
        qrScanCountAtInvoke
      );
      const handleMismatchTime = performance.now() - handleMismatchStartTime;
      console.log(`  [PERF] Handle mismatch call time: ${handleMismatchTime.toFixed(2)}ms`);
      
      const totalTime = performance.now() - totalStartTime;
      console.log(`⚠️ [PROCESS OUTSIDE QR MISMATCH] Total time before modal: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`);
      console.log(`  End time: ${new Date().toISOString()}`);
      console.log(`📊 Breakdown: parse=${parseTime.toFixed(2)}ms, validation=${validationTime.toFixed(2)}ms, duplicateCheck=${duplicateCheckTime.toFixed(2)}ms, lookup=${lookupTime.toFixed(2)}ms, match=${matchTime.toFixed(2)}ms, mismatchCheck=${mismatchCheckTime.toFixed(2)}ms, expectedLot=${expectedLotTime.toFixed(2)}ms, setSelectedLot=${setSelectedLotTime.toFixed(2)}ms, handleMismatch=${handleMismatchTime.toFixed(2)}ms`);
    } catch (error) {
      const totalTime = performance.now() - totalStartTime;
      console.error(`❌ [PROCESS OUTSIDE QR ERROR] Total time: ${totalTime.toFixed(2)}ms`);
      console.error("Error during QR code processing:", error);
      startTransition(() => {
        setQrScanError(true);
        setQrScanSuccess(false);
      });
      return;
    }
  }, [lotDataIndexes, handleLotMismatch, processedQrCombinations, combinedLotData, fetchStockInLineInfoCached]);
  // Store processOutsideQrCode in ref for immediate access (update on every render)
  processOutsideQrCodeRef.current = processOutsideQrCode;
  
  useEffect(() => {
    // Skip if scanner is not active or no data available
    if (!isManualScanning || qrValues.length === 0 || combinedLotData.length === 0 || isRefreshingData) {
      return;
    }
  
    const qrValuesChangeStartTime = performance.now();
    console.log(`  [QR VALUES EFFECT] Triggered at: ${new Date().toISOString()}`);
    console.log(`  [QR VALUES EFFECT] qrValues.length: ${qrValues.length}`);
    console.log(`  [QR VALUES EFFECT] qrValues:`, qrValues);
  
    const latestQr = qrValues[qrValues.length - 1];
    console.log(`  [QR VALUES EFFECT] Latest QR: ${latestQr}`);
    console.log(`  [QR VALUES EFFECT] Latest QR detected at: ${new Date().toISOString()}`);
    
    // ✅ FIXED: Handle test shortcut {2fitestx,y} or {2fittestx,y} where x=itemId, y=stockInLineId
    // Support both formats: {2fitest (2 t's) and {2fittest (3 t's)
    if ((latestQr.startsWith("{2fitest") || latestQr.startsWith("{2fittest")) && latestQr.endsWith("}")) {
      // Extract content: remove "{2fitest" or "{2fittest" and "}"
      let content = '';
      if (latestQr.startsWith("{2fittest")) {
        content = latestQr.substring(9, latestQr.length - 1); // Remove "{2fittest" and "}"
      } else if (latestQr.startsWith("{2fitest")) {
        content = latestQr.substring(8, latestQr.length - 1); // Remove "{2fitest" and "}"
      }
      
      const parts = content.split(',');
      
      if (parts.length === 2) {
        const itemId = parseInt(parts[0].trim(), 10);
        const stockInLineId = parseInt(parts[1].trim(), 10);
        
        if (!isNaN(itemId) && !isNaN(stockInLineId)) {
          console.log(
            `%c TEST QR: Detected ${latestQr.substring(0, 9)}... - Simulating QR input (itemId=${itemId}, stockInLineId=${stockInLineId})`,
            "color: purple; font-weight: bold"
          );
          
          // ✅ Simulate QR code JSON format
          const simulatedQr = JSON.stringify({
            itemId: itemId,
            stockInLineId: stockInLineId
          });
          
          console.log(`  [TEST QR] Simulated QR content: ${simulatedQr}`);
          console.log(`  [TEST QR] Start time: ${new Date().toISOString()}`);
          const testStartTime = performance.now();
          
          // ✅ Mark as processed FIRST to avoid duplicate processing
          lastProcessedQrRef.current = latestQr;
          processedQrCodesRef.current.add(latestQr);
          if (processedQrCodesRef.current.size > 100) {
            const firstValue = processedQrCodesRef.current.values().next().value;
            if (firstValue !== undefined) {
              processedQrCodesRef.current.delete(firstValue);
            }
          }
          setLastProcessedQr(latestQr);
          setProcessedQrCodes(new Set(processedQrCodesRef.current));
          
          // ✅ Process immediately (bypass QR scanner delay)
          if (processOutsideQrCodeRef.current) {
            processOutsideQrCodeRef.current(simulatedQr, qrValues.length).then(() => {
              const testTime = performance.now() - testStartTime;
              console.log(`  [TEST QR] Total processing time: ${testTime.toFixed(2)}ms (${(testTime / 1000).toFixed(3)}s)`);
              console.log(`  [TEST QR] End time: ${new Date().toISOString()}`);
            }).catch((error) => {
              const testTime = performance.now() - testStartTime;
              console.error(`❌ [TEST QR] Error after ${testTime.toFixed(2)}ms:`, error);
            });
          }
          
          // Reset scan
          if (resetScanRef.current) {
            resetScanRef.current();
          }
          
          const qrValuesChangeTime = performance.now() - qrValuesChangeStartTime;
          console.log(`  [QR VALUES EFFECT] Test QR handling time: ${qrValuesChangeTime.toFixed(2)}ms`);
          return; // ✅ IMPORTANT: Return early to prevent normal processing
        } else {
          console.warn(`  [TEST QR] Invalid itemId or stockInLineId: itemId=${parts[0]}, stockInLineId=${parts[1]}`);
        }
      } else {
        console.warn(`  [TEST QR] Invalid format. Expected {2fitestx,y} or {2fittestx,y}, got: ${latestQr}`);
      }
    }
    
    // 批次确认弹窗：须第二次扫码选择沿用建议批次或切换（不再自动确认）
    if (lotConfirmationOpen) {
      if (isConfirmingLot) {
        return;
      }
      if (lotConfirmSkipNextScanRef.current) {
        lotConfirmSkipNextScanRef.current = false;
        lotConfirmLastQrRef.current = latestQr || '';
        return;
      }
      if (!latestQr) {
        return;
      }
      // Prevent auto-accept from buffered duplicate right after modal opens,
      // but allow intentional second scan of the same QR after debounce window.
      const sameQr = latestQr === lotConfirmLastQrRef.current;
      const justOpened = lotConfirmOpenedAtRef.current > 0 && (Date.now() - lotConfirmOpenedAtRef.current) < 800;
      if (sameQr && justOpened) {
        return;
      }
      lotConfirmLastQrRef.current = latestQr;
      void (async () => {
        try {
          const handled = await handleLotConfirmationByRescan(latestQr);
          if (handled && resetScanRef.current) {
            resetScanRef.current();
          }
        } catch (e) {
          console.error("Lot confirmation rescan failed:", e);
        }
      })();
      return;
    }

    // Skip processing if manual confirmation modal is open
    if (manualLotConfirmationOpen) {
      // Check if this is a different QR code than what triggered the modal
      const modalTriggerQr = lastProcessedQrRef.current;
      if (latestQr === modalTriggerQr) {
        console.log(`  [QR PROCESS] Skipping - manual modal open for same QR`);
        return;
      }
      // If it's a different QR, allow processing
      console.log(`  [QR PROCESS] Different QR detected while manual modal open, allowing processing`);
    }
    
    const qrDetectionStartTime = performance.now();
    console.log(`  [QR DETECTION] Latest QR detected: ${latestQr?.substring(0, 50)}...`);
    console.log(`  [QR DETECTION] Detection time: ${new Date().toISOString()}`);
    console.log(`  [QR DETECTION] Time since QR scanner set value: ${(qrDetectionStartTime - qrValuesChangeStartTime).toFixed(2)}ms`);
    
    // Skip if already processed (use refs to avoid dependency issues and delays)
    const checkProcessedStartTime = performance.now();
    if (processedQrCodesRef.current.has(latestQr) || lastProcessedQrRef.current === latestQr) {
      const checkTime = performance.now() - checkProcessedStartTime;
      console.log(`  [QR PROCESS] Already processed check time: ${checkTime.toFixed(2)}ms`);
      return;
    }
    const checkTime = performance.now() - checkProcessedStartTime;
    console.log(` [QR PROCESS] Not processed check time: ${checkTime.toFixed(2)}ms`);
    
    // Handle special shortcut
    if (latestQr === "{2fic}") {
      console.log("  Detected {2fic} shortcut - opening manual lot confirmation form");
      setManualLotConfirmationOpen(true);
      if (resetScanRef.current) {
        resetScanRef.current();
      }
      lastProcessedQrRef.current = latestQr;
      processedQrCodesRef.current.add(latestQr);
      if (processedQrCodesRef.current.size > 100) {
        const firstValue = processedQrCodesRef.current.values().next().value;
        if (firstValue !== undefined) {
          processedQrCodesRef.current.delete(firstValue);
        }
      }
      setLastProcessedQr(latestQr);
      setProcessedQrCodes(prev => {
        const newSet = new Set(prev);
        newSet.add(latestQr);
        if (newSet.size > 100) {
          const firstValue = newSet.values().next().value;
          if (firstValue !== undefined) {
            newSet.delete(firstValue);
          }
        }
        return newSet;
      });
      return;
    }
    
    // Process new QR code immediately (background mode - no modal)
    // Check against refs to avoid state update delays
    if (latestQr && latestQr !== lastProcessedQrRef.current) {
      const processingStartTime = performance.now();
      console.log(`  [QR PROCESS] Starting processing at: ${new Date().toISOString()}`);
      console.log(`  [QR PROCESS] Time since detection: ${(processingStartTime - qrDetectionStartTime).toFixed(2)}ms`);
      
      // ✅ Process immediately for better responsiveness
      // Clear any pending debounced processing
      if (qrProcessingTimeoutRef.current) {
        clearTimeout(qrProcessingTimeoutRef.current);
        qrProcessingTimeoutRef.current = null;
      }
      
      // Log immediately (console.log is synchronous)
      console.log(`  [QR PROCESS] Processing new QR code with enhanced validation: ${latestQr}`);
      
      // Update refs immediately (no state update delay) - do this FIRST
      const refUpdateStartTime = performance.now();
      lastProcessedQrRef.current = latestQr;
      processedQrCodesRef.current.add(latestQr);
      if (processedQrCodesRef.current.size > 100) {
        const firstValue = processedQrCodesRef.current.values().next().value;
        if (firstValue !== undefined) {
          processedQrCodesRef.current.delete(firstValue);
        }
      }
      const refUpdateTime = performance.now() - refUpdateStartTime;
      console.log(`  [QR PROCESS] Ref update time: ${refUpdateTime.toFixed(2)}ms`);
      
      // Process immediately in background - no modal/form needed, no delays
      // Use ref to avoid dependency issues
      const processCallStartTime = performance.now();
      if (processOutsideQrCodeRef.current) {
        processOutsideQrCodeRef.current(latestQr, qrValues.length).then(() => {
          const processCallTime = performance.now() - processCallStartTime;
          const totalProcessingTime = performance.now() - processingStartTime;
          console.log(`  [QR PROCESS] processOutsideQrCode call time: ${processCallTime.toFixed(2)}ms`);
          console.log(`  [QR PROCESS] Total processing time: ${totalProcessingTime.toFixed(2)}ms (${(totalProcessingTime / 1000).toFixed(3)}s)`);
        }).catch((error) => {
          const processCallTime = performance.now() - processCallStartTime;
          const totalProcessingTime = performance.now() - processingStartTime;
          console.error(`❌ [QR PROCESS] processOutsideQrCode error after ${processCallTime.toFixed(2)}ms:`, error);
          console.error(`❌ [QR PROCESS] Total processing time before error: ${totalProcessingTime.toFixed(2)}ms`);
        });
      }
      
      // Update state for UI (but don't block on it)
      const stateUpdateStartTime = performance.now();
      setLastProcessedQr(latestQr);
      setProcessedQrCodes(new Set(processedQrCodesRef.current));
      const stateUpdateTime = performance.now() - stateUpdateStartTime;
      console.log(`  [QR PROCESS] State update time: ${stateUpdateTime.toFixed(2)}ms`);
      
      const detectionTime = performance.now() - qrDetectionStartTime;
      const totalEffectTime = performance.now() - qrValuesChangeStartTime;
      console.log(`  [QR DETECTION] Total detection time: ${detectionTime.toFixed(2)}ms`);
      console.log(`  [QR VALUES EFFECT] Total effect time: ${totalEffectTime.toFixed(2)}ms`);
    }
    
    return () => {
      if (qrProcessingTimeoutRef.current) {
        clearTimeout(qrProcessingTimeoutRef.current);
        qrProcessingTimeoutRef.current = null;
      }
    };
  }, [qrValues, isManualScanning, isRefreshingData, combinedLotData.length, lotConfirmationOpen, manualLotConfirmationOpen, handleLotConfirmationByRescan, isConfirmingLot]);
const renderCountRef = useRef(0);
const renderStartTimeRef = useRef<number | null>(null);

// Track render performance
useEffect(() => {
  renderCountRef.current++;
  const now = performance.now();
  
  if (renderStartTimeRef.current !== null) {
    const renderTime = now - renderStartTimeRef.current;
    if (renderTime > 100) { // Only log slow renders (>100ms)
      console.log(`  [PERF] Render #${renderCountRef.current} took ${renderTime.toFixed(2)}ms, combinedLotData length: ${combinedLotData.length}`);
    }
    renderStartTimeRef.current = null;
  }
  
  // Track when lotConfirmationOpen changes
  if (lotConfirmationOpen) {
    renderStartTimeRef.current = performance.now();
    console.log(`  [PERF] Render triggered by lotConfirmationOpen=true`);
  }
}, [combinedLotData.length, lotConfirmationOpen]);
  // Auto-start scanner only once on mount
  const scannerInitializedRef = useRef(false);
  
  useEffect(() => {
    if (session && currentUserId && !initializationRef.current) {
      console.log(" Session loaded, initializing pick order...");
      initializationRef.current = true;
      
      //  Only fetch existing data, no auto-assignment
      fetchAllCombinedLotData();
    }
  }, [session, currentUserId, fetchAllCombinedLotData]);
  
  // Separate effect for auto-starting scanner (only once, prevents multiple resets)
  useEffect(() => {
    if (session && currentUserId && !scannerInitializedRef.current) {
      scannerInitializedRef.current = true;
      // ✅ Auto-start scanner on mount for tablet use (background mode - no modal)
      console.log("✅ Auto-starting QR scanner in background mode");
      setIsManualScanning(true);
      startScan();
    }
  }, [session, currentUserId, startScan]);

  //  Add event listener for manual assignment
  useEffect(() => {
    const handlePickOrderAssigned = () => {
      console.log("🔄 Pick order assigned event received, refreshing data...");
      fetchAllCombinedLotData();
    };

    window.addEventListener('pickOrderAssigned', handlePickOrderAssigned);
    
    return () => {
      window.removeEventListener('pickOrderAssigned', handlePickOrderAssigned);
    };
  }, [fetchAllCombinedLotData]);



  const handleManualInputSubmit = useCallback(() => {
    if (qrScanInput.trim() !== '') {
      handleQrCodeSubmit(qrScanInput.trim());
    }
  }, [qrScanInput, handleQrCodeSubmit]);

  //  Handle QR code submission from modal (internal scanning)
  const handleQrCodeSubmitFromModal = useCallback(async (lotNo: string) => {
    if (selectedLotForQr && selectedLotForQr.lotNo === lotNo) {
      console.log(` QR Code verified for lot: ${lotNo}`);
      
      const requiredQty = selectedLotForQr.requiredQty;
      const lotId = selectedLotForQr.lotId;
      
      // Create stock out line

      
      try {
        const stockOutLineUpdate = await updateStockOutLineStatus({
          id: selectedLotForQr.stockOutLineId,
          status: 'checked',
          qty: selectedLotForQr.stockOutLineQty || 0
        });
        console.log("Stock out line updated successfully!");
        setQrScanSuccess(true);
        setQrScanError(false);

        // Clear selected lot (scanner stays active)
        setSelectedLotForQr(null);
        
        // Set pick quantity
        const lotKey = `${selectedLotForQr.pickOrderLineId}-${lotId}`;
        setTimeout(() => {
          setPickQtyData(prev => ({
            ...prev,
            [lotKey]: requiredQty
          }));
          console.log(` Auto-set pick quantity to ${requiredQty} for lot ${lotNo}`);
        }, 500);
        
      
      } catch (error) {
        console.error("Error creating stock out line:", error);
      }
    }
  }, [selectedLotForQr]);


  const handlePickQtyChange = useCallback((lotKey: string, value: number | string) => {
    if (value === '' || value === null || value === undefined) {
      setPickQtyData(prev => ({
        ...prev,
        [lotKey]: 0
      }));
      return;
    }
    
    const numericValue = typeof value === 'string' ? parseFloat(value) : value;
    
    if (isNaN(numericValue)) {
      setPickQtyData(prev => ({
        ...prev,
        [lotKey]: 0
      }));
      return;
    }
    
    setPickQtyData(prev => ({
      ...prev,
      [lotKey]: numericValue
    }));
  }, []);

  const [autoAssignStatus, setAutoAssignStatus] = useState<'idle' | 'checking' | 'assigned' | 'no_orders'>('idle');
  const [autoAssignMessage, setAutoAssignMessage] = useState<string>('');
  const [completionStatus, setCompletionStatus] = useState<PickOrderCompletionResponse | null>(null);

  const checkAndAutoAssignNext = useCallback(async () => {
    if (!currentUserId) return;
    
    try {
      const completionResponse = await checkPickOrderCompletion(currentUserId);
      
      if (completionResponse.code === "SUCCESS" && completionResponse.entity?.hasCompletedOrders) {
        console.log("Found completed pick orders, auto-assigning next...");
        //  移除前端的自动分配逻辑，因为后端已经处理了
        // await handleAutoAssignAndRelease(); // 删除这个函数
      }
    } catch (error) {
      console.error("Error checking pick order completion:", error);
    }
  }, [currentUserId]);
  const resolveSingleSubmitQty = useCallback(
    (lot: any) => {
      const required = Number(lot.requiredQty || lot.pickOrderLineRequiredQty || 0);
      const solId = Number(lot.stockOutLineId) || 0;
      const lotKey = `${lot.pickOrderLineId}-${lot.lotId}`;
      const issuePicked = solId > 0 ? issuePickedQtyBySolId[solId] : undefined;
      if (issuePicked !== undefined && !Number.isNaN(Number(issuePicked))) {
        return Number(issuePicked);
      }
      const fromPick = pickQtyData[lotKey];
      if (fromPick !== undefined && fromPick !== null && !Number.isNaN(Number(fromPick))) {
        return Number(fromPick);
      }
      if (lot.noLot === true) {
        return 0;
      }
      if (isInventoryLotLineUnavailable(lot)) {
        return 0;
      }
      if (isLotAvailabilityExpired(lot)) {
        return 0;
      }
      return required;
    },
    [issuePickedQtyBySolId, pickQtyData]
  );
  //  Handle reject lot
  //  Handle pick execution form
  const handlePickExecutionForm = useCallback((lot: any) => {
    console.log("=== Pick Execution Form ===");
    console.log("Lot data:", lot);
    
    if (!lot) {
      console.warn("No lot data provided for pick execution form");
      return;
    }
    
    console.log("Opening pick execution form for lot:", lot.lotNo);
    
    setSelectedLotForExecutionForm(lot);
    setPickExecutionFormOpen(true);
    
    console.log("Pick execution form opened for lot ID:", lot.lotId);
  }, []);

  const handlePickExecutionFormSubmit = useCallback(async (data: any) => {
    try {
      console.log("Pick execution form submitted:", data);
      const issueData = {
        ...data,
        type: "Do",  // Delivery Order Record 类型
        pickerName: session?.user?.name || '',
      };
      
      const result = await recordPickExecutionIssue(issueData);
      console.log("Pick execution issue recorded:", result);
      
      if (result && result.code === "SUCCESS") {
        console.log(" Pick execution issue recorded successfully");
        // 关键：issue form 只记录问题，不会更新 SOL.qty
        // 但 batch submit 需要知道“实际拣到多少”，否则会按 requiredQty 补拣到满
        const solId = Number(issueData.stockOutLineId || issueData.stockOutLineId === 0 ? issueData.stockOutLineId : data?.stockOutLineId);
        if (solId > 0) {
          const picked = Number(issueData.actualPickQty || 0);
          setIssuePickedQtyBySolId((prev) => {
            const next = { ...prev, [solId]: picked };
            const doId = fgPickOrders[0]?.doPickOrderId;
            if (doId) saveIssuePickedMap(doId, next);
            return next;
          });
          setCombinedLotData(prev => prev.map(lot => {
            if (Number(lot.stockOutLineId) === solId) {
              return { ...lot, actualPickQty: picked, stockOutLineQty: picked };
            }
            return lot;
          }));
        }
      } else {
        console.error("  Failed to record pick execution issue:", result);
      }
      
      setPickExecutionFormOpen(false);
      setSelectedLotForExecutionForm(null);
      setQrScanError(false);
      setQrScanSuccess(false);
      setQrScanInput('');
      // ✅ Keep scanner active after form submission - don't stop scanning
      // Only clear processed QR codes for the specific lot, not all
      // setIsManualScanning(false); // Removed - keep scanner active
      // stopScan(); // Removed - keep scanner active
      // resetScan(); // Removed - keep scanner active
      // Don't clear all processed codes - only clear for this specific lot if needed
      await fetchAllCombinedLotData();
    } catch (error) {
      console.error("Error submitting pick execution form:", error);
    }
  }, [fetchAllCombinedLotData, session, fgPickOrders]);

  //  Calculate remaining required quantity
  const calculateRemainingRequiredQty = useCallback((lot: any) => {
    const requiredQty = lot.requiredQty || 0;
    const stockOutLineQty = lot.stockOutLineQty || 0;
    return Math.max(0, requiredQty - stockOutLineQty);
  }, []);

  // Search criteria
  const searchCriteria: Criterion<any>[] = [
    {
      label: t("Pick Order Code"),
      paramName: "pickOrderCode",
      type: "text",
    },
      {
        label: t("Item Code"),
        paramName: "itemCode",
        type: "text",
      },
      {
        label: t("Item Name"),
        paramName: "itemName",
        type: "text",
      },
      {
      label: t("Lot No"),
      paramName: "lotNo",
      type: "text",
    },
  ];

  const handleSearch = useCallback((query: Record<string, any>) => {
    setSearchQuery({ ...query });
    console.log("Search query:", query);

    if (!originalCombinedData) return;

    const filtered = originalCombinedData.filter((lot: any) => {
      const pickOrderCodeMatch = !query.pickOrderCode || 
        lot.pickOrderCode?.toLowerCase().includes((query.pickOrderCode || "").toLowerCase());
      
        const itemCodeMatch = !query.itemCode || 
        lot.itemCode?.toLowerCase().includes((query.itemCode || "").toLowerCase());
        
        const itemNameMatch = !query.itemName || 
        lot.itemName?.toLowerCase().includes((query.itemName || "").toLowerCase());
      
      const lotNoMatch = !query.lotNo || 
        lot.lotNo?.toLowerCase().includes((query.lotNo || "").toLowerCase());
      
      return pickOrderCodeMatch && itemCodeMatch && itemNameMatch && lotNoMatch;
    });
    
    setCombinedLotData(filtered);
    console.log("Filtered lots count:", filtered.length);
  }, [originalCombinedData]);

  const handleReset = useCallback(() => {
    setSearchQuery({});
    if (originalCombinedData) {
      setCombinedLotData(originalCombinedData);
    }
  }, [originalCombinedData]);

  const handlePageChange = useCallback((event: unknown, newPage: number) => {
    setPaginationController(prev => ({
      ...prev,
      pageNum: newPage,
    }));
  }, []);

  const handlePageSizeChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
    const newPageSize = parseInt(event.target.value, 10);
    setPaginationController({
      pageNum: 0,
      pageSize: newPageSize === -1 ? -1 : newPageSize,
    });
  }, []);

  // Pagination data with sorting by routerIndex
 // Remove the sorting logic and just do pagination
// ✅ Memoize paginatedData to prevent re-renders when modal opens
const paginatedData = useMemo(() => {
  if (paginationController.pageSize === -1) {
    return combinedLotData; // Show all items
  }
  const startIndex = paginationController.pageNum * paginationController.pageSize;
  const endIndex = startIndex + paginationController.pageSize;
  return combinedLotData.slice(startIndex, endIndex); //  No sorting needed
}, [combinedLotData, paginationController.pageNum, paginationController.pageSize]);
const allItemsReady = useMemo(() => {
  if (combinedLotData.length === 0) return false;

  return combinedLotData.every((lot: any) => {
    const status = lot.stockOutLineStatus?.toLowerCase();
    const isRejected =
      status === 'rejected' || lot.lotAvailability === 'rejected';
    const isCompleted =
      status === 'completed' || status === 'partially_completed' || status === 'partially_complete';
    const isChecked = status === 'checked';
    const isPending = status === 'pending';

    // ✅ FIXED: 无库存（noLot）行：pending 状态也应该被视为 ready（可以提交）
    // ✅ 過期批號（未換批）：與 noLot 相同，視為可收尾
    if (lot.noLot === true || isLotAvailabilityExpired(lot) || isInventoryLotLineUnavailable(lot)) {
      return isChecked || isCompleted || isRejected || isPending;
    }

    // 正常 lot：必须已扫描/提交或者被拒收
    return isChecked || isCompleted || isRejected;
  });
}, [combinedLotData]);
const handleSubmitPickQtyWithQty = useCallback(async (lot: any, submitQty: number, source: 'justComplete' | 'singleSubmit') => {
  if (!lot.stockOutLineId) {
    console.error("No stock out line found for this lot");
    return;
  }
  const solId = Number(lot.stockOutLineId);
  if (solId > 0 && actionBusyBySolId[solId]) {
    console.warn("Action already in progress for stockOutLineId:", solId);
    return;
  }
  
  try {
    if (solId > 0) setActionBusyBySolId(prev => ({ ...prev, [solId]: true }));
    const targetUnavailable = isInventoryLotLineUnavailable(lot);
    const effectiveSubmitQty = targetUnavailable && submitQty > 0 ? 0 : submitQty;
    // Just Complete: mark checked only, real posting happens in batch submit
    if (effectiveSubmitQty === 0 && source === 'justComplete') {
      console.log(`=== SUBMITTING ALL ZEROS CASE ===`);
      console.log(`Lot: ${lot.lotNo}`);
      console.log(`Stock Out Line ID: ${lot.stockOutLineId}`);
      console.log(`Setting status to 'checked' with qty: 0`);
      
      const updateResult = await updateStockOutLineStatus({
        id: lot.stockOutLineId,
        status: 'checked',
        qty: 0
      });
      
      console.log('Update result:', updateResult);
      const r: any = updateResult as any;
      const updateOk =
        r?.code === 'SUCCESS' ||
        r?.type === 'completed' ||
        typeof r?.id === 'number' ||
        typeof r?.entity?.id === 'number' ||
        (r?.message && r.message.includes('successfully'));
      if (!updateResult || !updateOk) {
        console.error('Failed to update stock out line status:', updateResult);
        throw new Error('Failed to update stock out line status');
      }
      applyLocalStockOutLineUpdate(Number(lot.stockOutLineId), "checked", Number(lot.actualPickQty || 0));
      
      void fetchAllCombinedLotData();
      console.log("Just Complete marked as checked successfully (waiting for batch submit).");
      
      setTimeout(() => {
        checkAndAutoAssignNext();
      }, 1000);
      
      return;
    }
    if (effectiveSubmitQty === 0 && source === 'singleSubmit') {
      console.log(`=== SUBMITTING ALL ZEROS CASE ===`);
      console.log(`Lot: ${lot.lotNo}`);
      console.log(`Stock Out Line ID: ${lot.stockOutLineId}`);
      console.log(`Setting status to 'checked' with qty: 0`);
      
      const updateResult = await updateStockOutLineStatus({
        id: lot.stockOutLineId,
        status: 'checked',
        qty: 0
      });
      
      console.log('Update result:', updateResult);
      const r: any = updateResult as any;
      const updateOk =
        r?.code === 'SUCCESS' ||
        r?.type === 'completed' ||
        typeof r?.id === 'number' ||
        typeof r?.entity?.id === 'number' ||
        (r?.message && r.message.includes('successfully'));
      if (!updateResult || !updateOk) {
        console.error('Failed to update stock out line status:', updateResult);
        throw new Error('Failed to update stock out line status');
      }
      applyLocalStockOutLineUpdate(Number(lot.stockOutLineId), "checked", Number(lot.actualPickQty || 0));
      
      void fetchAllCombinedLotData();
      console.log("Just Complete marked as checked successfully (waiting for batch submit).");
      
      setTimeout(() => {
        checkAndAutoAssignNext();
      }, 1000);
      
      return;
    }
    //  FIXED: Calculate cumulative quantity correctly
    const currentActualPickQty = lot.actualPickQty || 0;
    const cumulativeQty = currentActualPickQty + effectiveSubmitQty;
    
    //  FIXED: Determine status based on cumulative quantity vs required quantity
    let newStatus = 'partially_completed';
    
    if (cumulativeQty >= lot.requiredQty) {
      newStatus = 'completed';
    } else if (cumulativeQty > 0) {
      newStatus = 'partially_completed';
    } else {
      newStatus = 'checked'; // QR scanned but no quantity submitted yet
    }
    
    console.log(`=== PICK QUANTITY SUBMISSION DEBUG ===`);
    console.log(`Lot: ${lot.lotNo}`);
    console.log(`Required Qty: ${lot.requiredQty}`);
    console.log(`Current Actual Pick Qty: ${currentActualPickQty}`);
    console.log(`New Submitted Qty: ${effectiveSubmitQty}`);
    console.log(`Cumulative Qty: ${cumulativeQty}`);
    console.log(`New Status: ${newStatus}`);
    console.log(`=====================================`);
    
    await updateStockOutLineStatus({
      id: lot.stockOutLineId,
      status: newStatus,
      // 后端 updateStatus 的 qty 是“增量 delta”，不能传 cumulativeQty（否则会重复累加导致 out/hold 大幅偏移）
      qty: effectiveSubmitQty
    });
    applyLocalStockOutLineUpdate(Number(lot.stockOutLineId), newStatus, cumulativeQty);
    // 注意：库存过账（hold->out）与 ledger 由后端 updateStatus 内部统一处理；
    // 前端不再额外调用 updateInventoryLotLineQuantities(operation='pick')，避免 double posting。
    
    //  Check if pick order is completed when lot status becomes 'completed'
    if (newStatus === 'completed' && lot.pickOrderConsoCode) {
      console.log(` Lot ${lot.lotNo} completed, checking if pick order ${lot.pickOrderConsoCode} is complete...`);
      
      try {
        const completionResponse = await checkAndCompletePickOrderByConsoCode(lot.pickOrderConsoCode);
        console.log(` Pick order completion check result:`, completionResponse);
        
        if (completionResponse.code === "SUCCESS") {
          console.log(` Pick order ${lot.pickOrderConsoCode} completed successfully!`);
        } else if (completionResponse.message === "not completed") {
          console.log(`⏳ Pick order not completed yet, more lines remaining`);
        } else {
          console.error(`  Error checking completion: ${completionResponse.message}`);
        }
      } catch (error) {
        console.error("Error checking pick order completion:", error);
      }
    }
    
    void fetchAllCombinedLotData();
    console.log("Pick quantity submitted successfully!");
    
    setTimeout(() => {
      checkAndAutoAssignNext();
    }, 1000);
    
  } catch (error) {
    console.error("Error submitting pick quantity:", error);
  } finally {
    if (solId > 0) setActionBusyBySolId(prev => ({ ...prev, [solId]: false }));
  }
}, [fetchAllCombinedLotData, checkAndAutoAssignNext, actionBusyBySolId, applyLocalStockOutLineUpdate]);

const handleSkip = useCallback(async (lot: any) => {
  try {
    console.log("Just Complete clicked, mark checked with 0 qty for lot:", lot.lotNo);
    await handleSubmitPickQtyWithQty(lot, 0, 'justComplete');
  } catch (err) {
    console.error("Error in Skip:", err);
  }
}, [handleSubmitPickQtyWithQty]);
const hasPendingBatchSubmit = useMemo(() => {
  return combinedLotData.some((lot) => {
    const status = String(lot.stockOutLineStatus || "").toLowerCase();
    return status === "checked" || status === "pending" || status === "partially_completed" || status === "partially_complete";
  });
}, [combinedLotData]);
useEffect(() => {
  if (!hasPendingBatchSubmit) return;
  const handler = (event: BeforeUnloadEvent) => {
    event.preventDefault();
    event.returnValue = "";
  };
  window.addEventListener("beforeunload", handler);
  return () => window.removeEventListener("beforeunload", handler);
}, [hasPendingBatchSubmit]);
const handleStartScan = useCallback(() => {
  const startTime = performance.now();
  console.log(`  [START SCAN] Called at: ${new Date().toISOString()}`);
  console.log(`  [START SCAN] Starting manual QR scan...`);
  
  setIsManualScanning(true);
  const setManualScanningTime = performance.now() - startTime;
  console.log(`  [START SCAN] setManualScanning time: ${setManualScanningTime.toFixed(2)}ms`);
  
  setProcessedQrCodes(new Set());
  setLastProcessedQr('');
  setQrScanError(false);
  setQrScanSuccess(false);
  
  const beforeStartScanTime = performance.now();
  startScan();
  const startScanTime = performance.now() - beforeStartScanTime;
  console.log(`  [START SCAN] startScan() call time: ${startScanTime.toFixed(2)}ms`);
  
  const totalTime = performance.now() - startTime;
  console.log(`  [START SCAN] Total start scan time: ${totalTime.toFixed(2)}ms`);
  console.log(`  [START SCAN] Start scan completed at: ${new Date().toISOString()}`);
}, [startScan]);
  const handlePickOrderSwitch = useCallback(async (pickOrderId: number) => {
    if (pickOrderSwitching) return;
    
    setPickOrderSwitching(true);
    try {
      console.log("  Switching to pick order:", pickOrderId);
      setSelectedPickOrderId(pickOrderId);
      
      //  强制刷新数据，确保显示正确的 pick order 数据
      await fetchAllCombinedLotData(currentUserId, pickOrderId);
    } catch (error) {
      console.error("Error switching pick order:", error);
    } finally {
      setPickOrderSwitching(false);
      }
    }, [pickOrderSwitching, currentUserId, fetchAllCombinedLotData]);
 
  const handleStopScan = useCallback(() => {
    console.log("⏸️ Pausing QR scanner...");
    setIsManualScanning(false);
    setQrScanError(false);
    setQrScanSuccess(false);
    stopScan();
    resetScan();
  }, [stopScan, resetScan]);
  // ... existing code around line 1469 ...
  const handlelotnull = useCallback(async (lot: any) => {
    //  优先使用 stockouts 中的 id，如果没有则使用 stockOutLineId
    const stockOutLineId = lot.stockOutLineId;
    
    if (!stockOutLineId) {
      console.error("  No stockOutLineId found for lot:", lot);
      return;
    }
    const solId = Number(stockOutLineId);
    if (solId > 0 && actionBusyBySolId[solId]) {
      console.warn("Action already in progress for stockOutLineId:", solId);
      return;
    }
    
    try {
      if (solId > 0) setActionBusyBySolId(prev => ({ ...prev, [solId]: true }));
      //  Step 1: Update stock out line status
      await updateStockOutLineStatus({
        id: stockOutLineId,
        status: 'completed',
        qty: 0
      });
      
      //  Step 2: Create pick execution issue for no-lot case
      // Get pick order ID from fgPickOrders or use 0 if not available
      const pickOrderId = lot.pickOrderId || fgPickOrders[0]?.pickOrderId || 0;
      const pickOrderCode = lot.pickOrderCode || fgPickOrders[0]?.pickOrderCode || lot.pickOrderConsoCode || '';
      
      const issueData: PickExecutionIssueData = {
        type: "Do",  // Delivery Order type
        pickOrderId: pickOrderId,
        pickOrderCode: pickOrderCode,
        pickOrderCreateDate: dayjs().format('YYYY-MM-DD'), //  Use dayjs format
        pickExecutionDate: dayjs().format('YYYY-MM-DD'),
        pickOrderLineId: lot.pickOrderLineId,
        itemId: lot.itemId,
        itemCode: lot.itemCode || '',
        itemDescription: lot.itemName || '',
        lotId: null, //  No lot available
        lotNo: null, //  No lot number
        storeLocation: lot.location || '',
        requiredQty: lot.requiredQty || lot.pickOrderLineRequiredQty || 0,
        actualPickQty: 0, //  No items picked (no lot available)
        missQty: lot.requiredQty || lot.pickOrderLineRequiredQty || 0, //  All quantity is missing
        badItemQty: 0,
        issueRemark: `No lot available for this item. Handled via handlelotnull.`,
        pickerName: session?.user?.name || '',
        
      };
      
      const result = await recordPickExecutionIssue(issueData);
      console.log(" Pick execution issue created for no-lot item:", result);
      
      if (result && result.code === "SUCCESS") {
        console.log(" No-lot item handled and issue recorded successfully");
      } else {
        console.error("  Failed to record pick execution issue:", result);
      }
      
      //  Step 3: Refresh data
      await fetchAllCombinedLotData();
    } catch (error) {
      console.error("  Error in handlelotnull:", error);
    } finally {
      if (solId > 0) setActionBusyBySolId(prev => ({ ...prev, [solId]: false }));
    }
  }, [fetchAllCombinedLotData, session, currentUserId, fgPickOrders, actionBusyBySolId]);
  const handleBatchScan = useCallback(async () => {
    const startTime = performance.now();
    console.log(`  [BATCH SCAN START]`);
    console.log(`  Start time: ${new Date().toISOString()}`);
    
    // 获取所有活跃批次（未扫描的）
    const activeLots = combinedLotData.filter(lot => {
      return (
        lot.lotAvailability !== 'rejected' &&
        lot.stockOutLineStatus !== 'rejected' &&
        lot.stockOutLineStatus !== 'completed' &&
        lot.stockOutLineStatus !== 'checked' && // ✅ 只处理未扫描的
        lot.processingStatus !== 'completed' &&
        lot.noLot !== true &&
        lot.lotNo // ✅ 必须有 lotNo
      );
    });
    
    if (activeLots.length === 0) {
      console.log("No active lots to scan");
      return;
    }
    
    console.log(`📦 Batch scanning ${activeLots.length} active lots using batch API...`);
    
    try {
      // ✅ 转换为批量扫描 API 所需的格式
      const lines: BatchScanLineRequest[] = activeLots.map((lot) => ({
        pickOrderLineId: Number(lot.pickOrderLineId),
        inventoryLotLineId: lot.lotId ? Number(lot.lotId) : null,
        pickOrderConsoCode: String(lot.pickOrderConsoCode || ''),
        lotNo: lot.lotNo || null,
        itemId: Number(lot.itemId),
        itemCode: String(lot.itemCode || ''),
        stockOutLineId: lot.stockOutLineId ? Number(lot.stockOutLineId) : null, // ✅ 新增
      }));
      
      const request: BatchScanRequest = {
        userId: currentUserId || 0,
        lines: lines
      };
      
      console.log(`📤 Sending batch scan request with ${lines.length} lines`);
      console.log(`📋 Request data:`, JSON.stringify(request, null, 2));
      
      const scanStartTime = performance.now();
      
      // ✅ 使用新的批量扫描 API（一次性处理所有请求）
      const result = await batchScan(request);
      
      const scanTime = performance.now() - scanStartTime;
      console.log(`  Batch scan API call completed in ${scanTime.toFixed(2)}ms (${(scanTime / 1000).toFixed(3)}s)`);
      console.log(`📥 Batch scan result:`, result);
      
      // ✅ 刷新数据以获取最新的状态
      const refreshStartTime = performance.now();
      await fetchAllCombinedLotData();
      const refreshTime = performance.now() - refreshStartTime;
      console.log(`  Data refresh time: ${refreshTime.toFixed(2)}ms (${(refreshTime / 1000).toFixed(3)}s)`);
      
      const totalTime = performance.now() - startTime;
      console.log(`  [BATCH SCAN END]`);
      console.log(`  Total time: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`);
      console.log(`  End time: ${new Date().toISOString()}`);
      
      if (result && result.code === "SUCCESS") {
        setQrScanSuccess(true);
        setQrScanError(false);
      } else {
        console.error("❌ Batch scan failed:", result);
        setQrScanError(true);
        setQrScanSuccess(false);
      }
      
    } catch (error) {
      console.error("❌ Error in batch scan:", error);
      setQrScanError(true);
      setQrScanSuccess(false);
    }
  }, [combinedLotData, fetchAllCombinedLotData, currentUserId]);
const handleSubmitAllScanned = useCallback(async () => {
  const startTime = performance.now();
  console.log(`  [BATCH SUBMIT START]`);
  console.log(`  Start time: ${new Date().toISOString()}`);
  
  const scannedLots = combinedLotData.filter(lot => {
    const status = lot.stockOutLineStatus;
    const statusLower = String(status || "").toLowerCase();
    if (statusLower === "completed" || statusLower === "complete") {
      return false;
    }
    // ✅ noLot / 過期批號：與 noLot 相同，允許 pending（未換批也可批量收尾）
    if (lot.noLot === true || isLotAvailabilityExpired(lot) || isInventoryLotLineUnavailable(lot)) {
      return (
        status === "checked" ||
        status === "pending" ||
        status === "partially_completed" ||
        status === "PARTIALLY_COMPLETE"
      );
    }
    return (
      status === "checked" ||
      status === "partially_completed" ||
      status === "PARTIALLY_COMPLETE"
    );
  });
  
  if (scannedLots.length === 0) {
    console.log("No scanned items to submit");
    return;
  }
  
  setIsSubmittingAll(true);
  console.log(`📦 Submitting ${scannedLots.length} scanned items using batchSubmitList...`);
  
  try {
    // 转换为 batchSubmitList 所需的格式（与后端 QrPickBatchSubmitRequest 匹配）
    const lines: batchSubmitListLineRequest[] = scannedLots.map((lot) => {
      // 1. 需求数量
      const requiredQty =
        Number(lot.requiredQty || lot.pickOrderLineRequiredQty || 0);
    
      // 2. 当前已经拣到的数量
      // issue form 不会写回 SOL.qty，所以如果这条 SOL 有 issue，就用 issue form 的 actualPickQty 作为“已拣到数量”
      const solId = Number(lot.stockOutLineId) || 0;
      const issuePicked = solId > 0 ? issuePickedQtyBySolId[solId] : undefined;
      const currentActualPickQty = Number(issuePicked ?? lot.actualPickQty ?? 0);
    
      // 🔹 判断是否走“只改状态模式”
      //   这里先给一个简单条件示例：如果你不想再补拣，只想把当前数量标记完成，
      //   就让这个条件为 true（后面你可以根据业务加 UI 开关或别的 flag）。
      const onlyComplete =
        lot.stockOutLineStatus === "partially_completed" || issuePicked !== undefined;

      const expired = isLotAvailabilityExpired(lot);
      const unavailable = isInventoryLotLineUnavailable(lot);

      let targetActual: number;
      let newStatus: string;

      // ✅ 過期且未在 Issue 填實際量：與 noLot 一樣按 0 完成
      if (unavailable) {
        targetActual = currentActualPickQty;
        newStatus = "completed";
      } else if (expired && issuePicked === undefined) {
        targetActual = 0;
        newStatus = "completed";
      } else if (onlyComplete) {
        targetActual = currentActualPickQty;
        newStatus = "completed";
      } else {
        const remainingQty = Math.max(0, requiredQty - currentActualPickQty);
        const cumulativeQty = currentActualPickQty + remainingQty;

        targetActual = cumulativeQty;

        newStatus = "partially_completed";
        if (requiredQty > 0 && cumulativeQty >= requiredQty) {
          newStatus = "completed";
        }
      }

      return {
        stockOutLineId: Number(lot.stockOutLineId) || 0,
        pickOrderLineId: Number(lot.pickOrderLineId),
        inventoryLotLineId: lot.lotId ? Number(lot.lotId) : null,
        requiredQty,
        // 后端用 targetActual - 当前 qty 算增量，onlyComplete 时就是 0
        actualPickQty: targetActual,
        stockOutLineStatus: newStatus,
        pickOrderConsoCode: String(lot.pickOrderConsoCode || ""),
        noLot: Boolean(lot.noLot === true),
      };
    });
    
    const request: batchSubmitListRequest = {
      userId: currentUserId || 0,
      lines: lines
    };
    
    console.log(`📤 Sending batch submit request with ${lines.length} lines`);
    console.log(`📋 Request data:`, JSON.stringify(request, null, 2));
    const submitStartTime = performance.now();
    
    // 使用 batchSubmitList API
    const result = await batchSubmitList(request);
    
    const submitTime = performance.now() - submitStartTime;
    console.log(`  Batch submit API call completed in ${submitTime.toFixed(2)}ms (${(submitTime / 1000).toFixed(3)}s)`);
    console.log(`📥 Batch submit result:`, result);
    
    // Refresh data once after batch submission
    const refreshStartTime = performance.now();
    await fetchAllCombinedLotData();
    const refreshTime = performance.now() - refreshStartTime;
    console.log(`  Data refresh time: ${refreshTime.toFixed(2)}ms (${(refreshTime / 1000).toFixed(3)}s)`);
    
    const totalTime = performance.now() - startTime;
    console.log(`  [BATCH SUBMIT END]`);
    console.log(`  Total time: ${totalTime.toFixed(2)}ms (${(totalTime / 1000).toFixed(3)}s)`);
    console.log(`  End time: ${new Date().toISOString()}`);
    
    if (result && result.code === "SUCCESS") {
      setQrScanSuccess(true);
      setTimeout(() => {
        setQrScanSuccess(false);
        checkAndAutoAssignNext();
        if (onSwitchToRecordTab) {
          onSwitchToRecordTab();
        }
        if (onRefreshReleasedOrderCount) {
          onRefreshReleasedOrderCount();
        }
      }, 2000);
    } else {
      console.error("Batch submit failed:", result);
      setQrScanError(true);
    }
    
  } catch (error) {
    console.error("Error submitting all scanned items:", error);
    setQrScanError(true);
  } finally {
    setIsSubmittingAll(false);
  }
}, [combinedLotData, fetchAllCombinedLotData, checkAndAutoAssignNext, currentUserId, onSwitchToRecordTab, onRefreshReleasedOrderCount, issuePickedQtyBySolId]);

  //  Calculate scanned items count
    //  Calculate scanned items count (should match handleSubmitAllScanned filter logic)
    const scannedItemsCount = useMemo(() => {
      const filtered = combinedLotData.filter(lot => {
        const status = lot.stockOutLineStatus;
      const statusLower = String(status || "").toLowerCase();
      if (statusLower === "completed" || statusLower === "complete") {
        return false;
      }
        // ✅ 与 handleSubmitAllScanned 完全保持一致
        if (lot.noLot === true || isLotAvailabilityExpired(lot) || isInventoryLotLineUnavailable(lot)) {
          return (
            status === "checked" ||
            status === "pending" ||
            status === "partially_completed" ||
            status === "PARTIALLY_COMPLETE"
          );
        }
        return (
          status === "checked" ||
          status === "partially_completed" ||
          status === "PARTIALLY_COMPLETE"
        );
      });
      
      //  添加调试日志
      const noLotCount = filtered.filter(l => l.noLot === true).length;
      const normalCount = filtered.filter(l => l.noLot !== true).length;
      console.log(`📊 scannedItemsCount calculation: total=${filtered.length}, noLot=${noLotCount}, normal=${normalCount}`);
      console.log(`📊 All items breakdown:`, {
        total: combinedLotData.length,
        noLot: combinedLotData.filter(l => l.noLot === true).length,
        normal: combinedLotData.filter(l => l.noLot !== true).length
      });
      
      return filtered.length;
    }, [combinedLotData]);
/*
  //  ADD THIS: Auto-stop scan when no data available
  useEffect(() => {
    if (isManualScanning && combinedLotData.length === 0) {
      console.log("⏹️ No data available, auto-stopping QR scan...");
      handleStopScan();
    }
  }, [combinedLotData.length, isManualScanning, handleStopScan]);
  */

  //  Cleanup effect
  useEffect(() => {
    return () => {
      // Cleanup when component unmounts (e.g., when switching tabs)
      if (isManualScanning) {
        console.log("🧹 Pick execution component unmounting, stopping QR scanner...");
        stopScan();
        resetScan();
      }
    };
  }, [isManualScanning, stopScan, resetScan]);

  const getStatusMessage = useCallback((lot: any) => {
    switch (lot.stockOutLineStatus?.toLowerCase()) {
      case 'pending':
        return t("Please finish QR code scan and pick order.");
      case 'checked':
        return t("Please submit the pick order.");
      case 'partially_completed':
        return t("Partial quantity submitted. Please submit more or complete the order.");
      case 'completed':
        return t("Pick order completed successfully!");
      case 'rejected':
        return t("Lot has been rejected and marked as unavailable.");
      case 'unavailable':
        return t("This order is insufficient, please pick another lot.");
      default:
        return t("Please finish QR code scan and pick order.");
    }
  }, [t]);
  return (
    <TestQrCodeProvider
      lotData={combinedLotData}
      onScanLot={handleQrCodeSubmit}
      onBatchScan={handleBatchScan}
      filterActive={(lot) => (
        lot.lotAvailability !== 'rejected' &&
        lot.stockOutLineStatus !== 'rejected' &&
        lot.stockOutLineStatus !== 'completed'
      )}
    >
      <FormProvider {...formProps}>
        <Stack spacing={2}>
        <Box
          sx={{
            position: 'fixed',
            top: 0,
            left: 0,
            right: 0,
            zIndex: 1100, // Higher than other elements
            backgroundColor: 'background.paper',
            pt: 2,
            pb: 1,
            px: 2,
            borderBottom: '1px solid',
            borderColor: 'divider',
            boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
          }}
        >
          <LinearProgressWithLabel
            completed={progress.completed}
            total={progress.total}
            label={t("Progress")}
          />
          <ScanStatusAlert
            error={qrScanError}
            success={qrScanSuccess}
            errorMessage={t("QR code does not match any item in current orders.")}
            successMessage={t("QR code verified.")}
          />
        </Box>
          {/* DO Header */}

  
        
  
  {/*  保留：Combined Lot Table - 包含所有 QR 扫描功能 */}
  <Box>
    <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2, mt: 10 }}>
      <Typography variant="h6" gutterBottom sx={{ mb: 0 }}>
        {t("All Pick Order Lots")}
      </Typography>
      
      <Box sx={{ display: 'flex', gap: 2, alignItems: 'center' }}>
        {/* Scanner status indicator (always visible) */}
        {/*
        <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
          <QrCodeIcon 
            sx={{ 
              color: isManualScanning ? '#4caf50' : '#9e9e9e',
              animation: isManualScanning ? 'pulse 2s infinite' : 'none',
              '@keyframes pulse': {
                '0%, 100%': { opacity: 1 },
                '50%': { opacity: 0.5 }
              }
            }} 
          />
          <Typography variant="body2" sx={{ color: isManualScanning ? '#4caf50' : '#9e9e9e' }}>
            {isManualScanning ? t("Scanner Active") : t("Scanner Inactive")}
          </Typography>
        </Box>
        */}
        
        {/* Pause/Resume button instead of Start/Stop */}
        {isManualScanning ? (
          <Button
            variant="outlined"
            startIcon={<QrCodeIcon />}
            onClick={handleStopScan}
            color="secondary"
            sx={{ minWidth: '120px' }}
          >
            {t("Stop QR Scan")}
          </Button>
        ) : (
          <Button
            variant="contained"
            startIcon={<QrCodeIcon />}
            onClick={handleStartScan}
            color="primary"
            sx={{ minWidth: '120px' }}
          >
            {t("Start QR Scan")}
          </Button>
        )}
        
        {/*  保留：Submit All Scanned Button */}
        <Button
          variant="contained"
          color="success"
          onClick={handleSubmitAllScanned}
          disabled={
            scannedItemsCount === 0
            || isSubmittingAll}
          sx={{ minWidth: '160px' }}
        >
          {isSubmittingAll ? (
            <>
              <CircularProgress size={16} sx={{ mr: 1, color: 'white' }} />
              {t("Submitting...")}
            </>
          ) : (
            `${t("Submit All Scanned")} (${scannedItemsCount})`
          )}
        </Button>
      </Box>
    </Box>

  
{fgPickOrders.length > 0 && (
  <Paper sx={{ p: 2, mb: 2 }}>
    <Stack spacing={2}>
      {/* 基本信息 */}
      <Stack direction="row" spacing={4} useFlexGap flexWrap="wrap">
        <Typography variant="subtitle1">
          <strong>{t("Shop Name")}:</strong> {fgPickOrders[0].shopName || '-'}
        </Typography>
        <Typography variant="subtitle1">
          <strong>{t("Store ID")}:</strong> {fgPickOrders[0].storeId || '-'}
        </Typography>
        <Typography variant="subtitle1">
          <strong>{t("Ticket No.")}:</strong> {fgPickOrders[0].ticketNo || '-'}
        </Typography>
        <Typography variant="subtitle1">
          <strong>{t("Departure Time")}:</strong> {fgPickOrders[0].DepartureTime || '-'}
        </Typography>
      </Stack>
      
      {/*  改进：三个字段显示在一起，使用表格式布局 */}
    {/*  改进：三个字段合并显示 */}
{/*  改进：表格式显示每个 pick order */}
<Box sx={{ 
  p: 2, 
  backgroundColor: '#f5f5f5', 
  borderRadius: 1 
}}>
  <Typography variant="subtitle2" sx={{ mb: 1, fontWeight: 'bold' }}>
    {t("Pick Orders Details")}:
  </Typography>
  
  {(() => {
    const pickOrderCodes = fgPickOrders[0].pickOrderCodes as string[] | string | undefined;
    const deliveryNos = fgPickOrders[0].deliveryNos as string[] | string | undefined;
    const lineCounts = fgPickOrders[0].lineCountsPerPickOrder;
    
    const pickOrderCodesArray = Array.isArray(pickOrderCodes) 
      ? pickOrderCodes 
      : (typeof pickOrderCodes === 'string' ? pickOrderCodes.split(', ') : []);
    
    const deliveryNosArray = Array.isArray(deliveryNos) 
      ? deliveryNos 
      : (typeof deliveryNos === 'string' ? deliveryNos.split(', ') : []);
    
    const lineCountsArray = Array.isArray(lineCounts) ? lineCounts : [];
    
    const maxLength = Math.max(
      pickOrderCodesArray.length, 
      deliveryNosArray.length, 
      lineCountsArray.length
    );
    
    if (maxLength === 0) {
      return <Typography variant="body2" color="text.secondary">-</Typography>;
    }
    
    //  使用与外部基本信息相同的样式
    return Array.from({ length: maxLength }, (_, idx) => (
      <Stack 
        key={idx} 
        direction="row" 
        spacing={4} 
        useFlexGap 
        flexWrap="wrap"
        sx={{ mb: idx < maxLength - 1 ? 1 : 0 }}  // 除了最后一行，都添加底部间距
      >
        <Typography variant="subtitle1">
          <strong>{t("Delivery Order")}:</strong> {deliveryNosArray[idx] || '-'}
        </Typography>
        <Typography variant="subtitle1">
          <strong>{t("Pick Order")}:</strong> {pickOrderCodesArray[idx] || '-'}
        </Typography>
        <Typography variant="subtitle1">
          <strong>{t("Finsihed good items")}:</strong> {lineCountsArray[idx] || '-'}<strong>{t("kinds")}</strong>
        </Typography>
      </Stack>
    ));
  })()}
</Box>
    </Stack>
  </Paper>
    )}
    

            <TableContainer component={Paper}>
              <Table>
                <TableHead>
                  <TableRow>
                    <TableCell>{t("Index")}</TableCell>
                    <TableCell>{t("Route")}</TableCell>
                    <TableCell>{t("Item Code")}</TableCell>
                    <TableCell>{t("Item Name")}</TableCell>
                    <TableCell>{t("Lot#")}</TableCell>
                    <TableCell align="right">{t("Lot Required Pick Qty")}</TableCell>
                    <TableCell align="center">{t("Scan Result")}</TableCell>
                    <TableCell align="center">{t("Qty will submit")}</TableCell>
                    <TableCell align="center">{t("Submit Required Pick Qty")}</TableCell>
                  </TableRow>
                </TableHead>
                <TableBody>
                  {paginatedData.length === 0 ? (
                    <TableRow>
                      <TableCell colSpan={11} align="center">
                        <Typography variant="body2" color="text.secondary">
                          {t("No data available")}
                        </Typography>
                      </TableCell>
                    </TableRow>
                  ) : (
// 在第 1797-1938 行之间，将整个 map 函数修改为：
paginatedData.map((lot, index) => {
  //  检查是否是 issue lot
  const isIssueLot = lot.stockOutLineStatus === 'rejected' || !lot.lotNo;
  
  return (
    <TableRow 
      key={`${lot.pickOrderLineId}-${lot.lotId || 'null'}`}
      sx={{
        //backgroundColor: isIssueLot ? '#fff3e0' : 'inherit',
       // opacity: isIssueLot ? 0.6 : 1,
        '& .MuiTableCell-root': {
          //color: isIssueLot ? 'warning.main' : 'inherit'
        }
      }}
    >
      <TableCell>
  <Typography variant="body2" fontWeight="bold">
    {paginationController.pageNum * paginationController.pageSize + index + 1}
  </Typography>
</TableCell>
      <TableCell>
        <Typography variant="body2">
          {lot.routerRoute || '-'}
        </Typography>
      </TableCell>
      <TableCell>{lot.itemCode}</TableCell>
      <TableCell>{lot.itemName + '(' + lot.stockUnit + ')'}</TableCell>
      <TableCell>
      <Box>
      <Typography
        sx={{
          color:
            isInventoryLotLineUnavailable(lot)
              ? 'error.main'
              : lot.lotAvailability === 'expired'
              ? 'warning.main'
              : 'inherit',
        }}
      >
        {lot.lotNo ? (
          isInventoryLotLineUnavailable(lot) ? (
            <>
              {lot.lotNo}{' '}
              {t('is unavable. Please check around have available QR code or not.')}
            </>
          ) : lot.lotAvailability === 'expired' ? (
            <>
              {lot.lotNo}{' '}
              {t('is expired. Please check around have available QR code or not.')}
            </>
          ) : (
            lot.lotNo
          )
        ) : (
          t(
            'Please check around have QR code or not, may be have just now stock in or transfer in or transfer out.'
          )
        )}
      </Typography>
    </Box>
      </TableCell>
      <TableCell align="right">
        {(() => {
          const requiredQty = lot.requiredQty || 0;
          return requiredQty.toLocaleString() + '(' + lot.uomShortDesc + ')';
        })()}
      </TableCell>
      
      <TableCell align="center">
  {(() => {
    const status = lot.stockOutLineStatus?.toLowerCase();
    const isRejected = status === 'rejected' || lot.lotAvailability === 'rejected';
    const isNoLot = !lot.lotNo;
    
    // rejected lot：显示红色勾选（已扫描但被拒绝）
    if (isRejected && !isNoLot) {
      return (
        <Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
          <Checkbox
            checked={true}
            disabled={true}
            readOnly={true}
            size="large"
            sx={{
              color: 'error.main',
              '&.Mui-checked': { color: 'error.main' },
              transform: 'scale(1.3)',
            }}
          />
        </Box>
      );
    }

    // 過期批號：與 noLot 同類——視為已掃到/可處理（含 pending），顯示警示色勾選
    if (isLotAvailabilityExpired(lot) && status !== "rejected") {
      return (
        <Box sx={{ display: "flex", justifyContent: "center", alignItems: "center" }}>
          <Checkbox
            checked={true}
            disabled={true}
            readOnly={true}
            size="large"
            sx={{
              color: "warning.main",
              "&.Mui-checked": { color: "warning.main" },
              transform: "scale(1.3)",
            }}
          />
        </Box>
      );
    }

    // 正常 lot：已扫描（checked/partially_completed/completed）
    if (!isNoLot && status !== 'pending' && status !== 'rejected') {
      return (
        <Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
          <Checkbox
            checked={true}
            disabled={true}
            readOnly={true}
            size="large"
            sx={{
              color: 'success.main',
              '&.Mui-checked': { color: 'success.main' },
              transform: 'scale(1.3)',
            }}
          />
        </Box>
      );
    }
    
    // noLot 且已完成/部分完成：显示红色勾选
    if (isNoLot && (status === 'partially_completed' || status === 'completed')) {
      return (
        <Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
          <Checkbox
            checked={true}
            disabled={true}
            readOnly={true}
            size="large"
            sx={{
              color: 'error.main',
              '&.Mui-checked': { color: 'error.main' },
              transform: 'scale(1.3)',
            }}
          />
        </Box>
      );
    }
    
    return null;
  })()}
</TableCell>
<TableCell align="center">
  {isInventoryLotLineUnavailable(lot) ? 0 : resolveSingleSubmitQty(lot)}
</TableCell>
<TableCell align="center">
  <Box sx={{ display: 'flex', justifyContent: 'center' }}>
    {(() => {
      const status = lot.stockOutLineStatus?.toLowerCase();
      const isRejected = status === 'rejected' || lot.lotAvailability === 'rejected';
      const isNoLot = !lot.lotNo;
      const isUnavailableLot = isInventoryLotLineUnavailable(lot);
      
      // ✅ rejected lot：显示提示文本（换行显示）
      if (isRejected && !isNoLot) {
        return (
          <Typography 
            variant="body2" 
            color="error.main"
            sx={{ 
              textAlign: 'center',
              whiteSpace: 'normal',
              wordBreak: 'break-word',
              maxWidth: '200px',
              lineHeight: 1.5
            }}
          >
            {t("This lot is rejected, please scan another lot.")}
          </Typography>
        );
      }
      
      // noLot 情况：只显示 Issue 按钮
      if (isNoLot) {
        return (
          <Button
            variant="outlined"
            size="small"
            onClick={() => handlelotnull(lot)}
            /*
            disabled={
              status === 'completed' ||
              (Number(lot.stockOutLineId) > 0 && actionBusyBySolId[Number(lot.stockOutLineId)] === true)
            }
            */
            disabled={true}
            sx={{ 
              fontSize: '0.7rem',
              py: 0.5,
              minHeight: '28px',
              minWidth: '60px',
              borderColor: 'warning.main',
              color: 'warning.main'
            }}
          >
            {t("Issue")}
          </Button>
        );
      }
      
      // 正常 lot：显示 Submit 和 Issue 按钮
      return (
        <Stack direction="row" spacing={1} alignItems="center">
          <Button
            variant="contained"
            onClick={() => {
              const lotKey = `${lot.pickOrderLineId}-${lot.lotId}`;
              const submitQty = resolveSingleSubmitQty(lot);
              handlePickQtyChange(lotKey, submitQty);
              handleSubmitPickQtyWithQty(lot, submitQty, 'singleSubmit');
            }}
            /*
            disabled={
              lot.lotAvailability === 'expired' || 
              isInventoryLotLineUnavailable(lot) || 
              lot.lotAvailability === 'rejected' ||
              lot.stockOutLineStatus === 'completed' ||
              lot.stockOutLineStatus === 'pending' ||
              (Number(lot.stockOutLineId) > 0 && actionBusyBySolId[Number(lot.stockOutLineId)] === true)
            }
*/
            disabled={true}

            sx={{ fontSize: '0.75rem', py: 0.5, minHeight: '28px', minWidth: '70px' }}
          >
            {t("Submit")}
          </Button>
          
          <Button
            variant="outlined"
            size="small"
            onClick={() => handlePickExecutionForm(lot)}
            
            disabled={
              lot.lotAvailability === 'expired' || 
              lot.stockOutLineStatus === 'completed' ||
              (Number(lot.stockOutLineId) > 0 && actionBusyBySolId[Number(lot.stockOutLineId)] === true)
            }
            
           // disabled={true}
            sx={{ 
              fontSize: '0.7rem',
              py: 0.5,
              minHeight: '28px',
              minWidth: '60px',
              borderColor: 'warning.main',
              color: 'warning.main'
            }}
            title="Report missing or bad items"
          >
            {t("Edit")}
          </Button>
          <Button
            variant="outlined"
            size="small"
            onClick={() => handleSkip(lot)}
            title={isUnavailableLot ? t('is unavable. Please check around have available QR code or not.') : undefined}
            
            disabled={
              lot.stockOutLineStatus === 'completed' ||
              lot.stockOutLineStatus === 'checked' ||
              lot.stockOutLineStatus === 'partially_completed' ||
              lot.lotAvailability === 'expired' ||
              isUnavailableLot ||

              // 使用 issue form 後，禁用「Just Completed」（避免再次点击造成重复提交）
              (Number(lot.stockOutLineId) > 0 && issuePickedQtyBySolId[Number(lot.stockOutLineId)] !== undefined) ||
              (Number(lot.stockOutLineId) > 0 && actionBusyBySolId[Number(lot.stockOutLineId)] === true)
            }
           

            sx={{ fontSize: '0.7rem', py: 0.5, minHeight: '28px', minWidth: '60px' }}
          >
            {t("Just Completed")}
          </Button>
        </Stack>
      );
    })()}
  </Box>
</TableCell>
    </TableRow>
  );
})
                  )}
                </TableBody>
              </Table>
            </TableContainer>
            
            <TablePagination
              component="div"
              count={combinedLotData.length}
              page={paginationController.pageNum}
              rowsPerPage={paginationController.pageSize}
              onPageChange={handlePageChange}
              onRowsPerPageChange={handlePageSizeChange}
              rowsPerPageOptions={[10, 25, 50,-1]}
              labelRowsPerPage={t("Rows per page")}
              labelDisplayedRows={({ from, to, count }) => 
                `${from}-${to} of ${count !== -1 ? count : `more than ${to}`}`
              }
            />
          </Box>
        </Stack>
  
        {/* QR Code Scanner works in background - no modal needed */}
        <ManualLotConfirmationModal
          open={manualLotConfirmationOpen}
          onClose={() => {
            setManualLotConfirmationOpen(false);
          }}
          onConfirm={handleManualLotConfirmation}
          expectedLot={expectedLotData}
          scannedLot={scannedLotData}
          isLoading={isConfirmingLot}
        />
        {/*  保留：Lot Confirmation Modal */}
        {lotConfirmationOpen && expectedLotData && scannedLotData && (
  <LotConfirmationModal
    open={lotConfirmationOpen}
    onClose={() => {
      console.log(`  [LOT CONFIRM MODAL] Closing modal, reset scanner and release raw-QR dedupe`);
      // 1) Reset scanner buffer first to avoid immediate reopen from buffered same QR.
      if (resetScanRef.current) {
        resetScanRef.current();
      }
      // 2) Close modal state.
      clearLotConfirmationState(false);
      // 3) Release raw-QR dedupe after a short delay so user can re-scan B/C again.
      setTimeout(() => {
        lastProcessedQrRef.current = '';
        processedQrCodesRef.current.clear();
      }, 250);
    }}
    onConfirm={handleLotConfirmation}
    expectedLot={expectedLotData}
    scannedLot={scannedLotData}
    isLoading={isConfirmingLot}
    errorMessage={lotConfirmationError}
  />
)}
        
        {/*  保留：Good Pick Execution Form Modal */}
        {pickExecutionFormOpen && selectedLotForExecutionForm && (
          <GoodPickExecutionForm
            open={pickExecutionFormOpen}
            onClose={() => {
              setPickExecutionFormOpen(false);
              setSelectedLotForExecutionForm(null);
            }}
            onSubmit={handlePickExecutionFormSubmit}
            selectedLot={selectedLotForExecutionForm}
            selectedPickOrderLine={{
              id: selectedLotForExecutionForm.pickOrderLineId,
              itemId: selectedLotForExecutionForm.itemId,
              itemCode: selectedLotForExecutionForm.itemCode,
              itemName: selectedLotForExecutionForm.itemName,
              pickOrderCode: selectedLotForExecutionForm.pickOrderCode,
              availableQty: selectedLotForExecutionForm.availableQty || 0,
              requiredQty: selectedLotForExecutionForm.requiredQty || 0,
             // uomCode: selectedLotForExecutionForm.uomCode || '',
              uomDesc: selectedLotForExecutionForm.uomDesc || '',
              pickedQty: selectedLotForExecutionForm.actualPickQty || 0,
              uomShortDesc: selectedLotForExecutionForm.uomShortDesc || '',
              suggestedList: [],
              noLotLines: [],
            }}
            pickOrderId={selectedLotForExecutionForm.pickOrderId}
            pickOrderCreateDate={new Date()}
          />
        )}
      </FormProvider>

  
    
      
    </TestQrCodeProvider>
  );
};

export default PickExecution;
