"use client";
import { QrCodeInfo } from "@/app/api/qrcode";
import { useRef } from "react";
import {
  ReactNode,
  createContext,
  useCallback,
  useContext,
  useEffect,
  useState,
  startTransition,
} from "react";

export interface QrCodeScanner {
  values: string[];
  isScanning: boolean;
  startScan: () => void;
  stopScan: () => void;
  resetScan: () => void;
  result: QrCodeInfo | undefined;
  state: "scanning" | "pending" | "retry";
  error: string | undefined;
}

interface QrCodeScannerProviderProps {
  children: ReactNode;
}

export const QrCodeScannerContext = createContext<QrCodeScanner | undefined>(
  undefined,
);

const QrCodeScannerProvider: React.FC<QrCodeScannerProviderProps> = ({
  children,
}) => {
  const [qrCodeScannerValues, setQrCodeScannerValues] = useState<string[]>([]);
  const [isScanning, setIsScanning] = useState<boolean>(false);
  const [keys, setKeys] = useState<string[]>([]);
  const [leftCurlyBraceCount, setLeftCurlyBraceCount] = useState<number>(0);
  const [rightCurlyBraceCount, setRightCurlyBraceCount] = useState<number>(0);
  const [scanResult, setScanResult] = useState<QrCodeInfo | undefined>()
  const [scanState, setScanState] = useState<"scanning" | "pending" | "retry">("pending");
  const [scanError, setScanError] = useState<string | undefined>()  // TODO return scan error message
  const keysRef = useRef<string[]>([]);
  const leftBraceCountRef = useRef<number>(0);
  const rightBraceCountRef = useRef<number>(0);
  const isFirstKeyRef = useRef<boolean>(true);

  const resetScannerInput = useCallback(() => {
    setKeys(() => []);
    setLeftCurlyBraceCount(() => 0);
    setRightCurlyBraceCount(() => 0);
  }, []);

  const resetQrCodeScanner = useCallback((error : string = "") => {
    setQrCodeScannerValues(() => []);
    setScanResult(undefined);
    resetScannerInput();

    console.log("%c Scanner Reset", "color:cyan");
    
    if (error.length > 0) {
      console.log("%c Error:", "color:red", error);
      console.log("%c key:", "color:red", keys);
      setScanState("retry");
    }
  }, []);

  const startQrCodeScanner = useCallback(() => {
    const startTime = performance.now();
    console.log(`⏱️ [SCANNER START] Called at: ${new Date().toISOString()}`);
    
    resetQrCodeScanner();
    const resetTime = performance.now() - startTime;
    console.log(`⏱️ [SCANNER START] Reset time: ${resetTime.toFixed(2)}ms`);
    
    setIsScanning(() => true);
    const setScanningTime = performance.now() - startTime;
    console.log(`⏱️ [SCANNER START] setScanning time: ${setScanningTime.toFixed(2)}ms`);
    
    const totalTime = performance.now() - startTime;
    console.log(`%c Scanning started `, "color:cyan");
    console.log(`⏱️ [SCANNER START] Total start time: ${totalTime.toFixed(2)}ms`);
    console.log(`⏰ [SCANNER START] Scanner started at: ${new Date().toISOString()}`);
  }, [resetQrCodeScanner]);

  const endQrCodeScanner = useCallback(() => {
    setIsScanning(() => false);
    console.log("%c Scanning stopped ", "color:cyan");
  }, []);

  // Find by rough match, return 0 if not found
  const findIdByRoughMatch = (inputString : string, keyword : string) => {
    console.log(`%c Performed rough match for ${keyword} within ${inputString}`, "color:brown");
    
    const keywordIndex = inputString.indexOf(keyword);
    
    let result : {keywordFound: boolean; number: number | null; message: string} = {
      keywordFound: false,
      number: null,
      message: `${keyword} not found in the input`,
    };

    if (keywordIndex !== -1) {
      const substringAfterKeyword = inputString.slice(keywordIndex + keyword.length);
      
      const numberMatch = substringAfterKeyword.match(/\d+/);
      
      if (!numberMatch) {
        result = {
          keywordFound: true,
          number: null,
          message: `No valid number found after ${keyword}`,
        };
      } else {
        result = {
          keywordFound: true,
          number: parseInt(numberMatch[0], 10),
          message: `Found ${keyword} at index ${keywordIndex}, first number found after is: ${numberMatch[0]}`,
        };
      }    
    }

    console.log(`%c ${result.message}`, "color:brown");
    return result;
  };

  useEffect(() => {
    const effectStartTime = performance.now();
    console.log(`⏱️ [KEYBOARD LISTENER EFFECT] Triggered at: ${new Date().toISOString()}`);
    console.log(`⏱️ [KEYBOARD LISTENER EFFECT] isScanning: ${isScanning}`);
    
    if (isScanning) {
      const listenerRegisterStartTime = performance.now();
      console.log(`⏱️ [KEYBOARD LISTENER] Registering keyboard listener at: ${new Date().toISOString()}`);
      
      // Reset refs when starting scan
      keysRef.current = [];
      leftBraceCountRef.current = 0;
      rightBraceCountRef.current = 0;
      isFirstKeyRef.current = true;
      
      const handleKeyDown = (event: KeyboardEvent) => {
        const keyPressTime = performance.now();
        const keyPressTimestamp = new Date().toISOString();
        
        // ✅ OPTIMIZED: Use refs to accumulate keys immediately (no state update delay)
        if (event.key.length === 1) {
          if (isFirstKeyRef.current) {
            console.log(`⏱️ [KEYBOARD] First key press detected: "${event.key}"`);
            console.log(`⏰ [KEYBOARD] First key press at: ${keyPressTimestamp}`);
            console.log(`⏱️ [KEYBOARD] Time since listener registered: ${(keyPressTime - listenerRegisterStartTime).toFixed(2)}ms`);
            isFirstKeyRef.current = false;
          }
          keysRef.current.push(event.key);
        }
  
        if (event.key === "{") {
          const braceTime = performance.now();
          console.log(`⏱️ [KEYBOARD] Left brace "{" detected at: ${new Date().toISOString()}`);
          console.log(`⏱️ [KEYBOARD] Time since listener registered: ${(braceTime - listenerRegisterStartTime).toFixed(2)}ms`);
          leftBraceCountRef.current += 1;
        } else if (event.key === "}") {
          const braceTime = performance.now();
          console.log(`⏱️ [KEYBOARD] Right brace "}" detected at: ${new Date().toISOString()}`);
          console.log(`⏱️ [KEYBOARD] Time since listener registered: ${(braceTime - listenerRegisterStartTime).toFixed(2)}ms`);
          rightBraceCountRef.current += 1;
          
          // ✅ OPTIMIZED: Check for complete QR immediately and update state only once
          if (leftBraceCountRef.current === rightBraceCountRef.current && leftBraceCountRef.current > 0) {
            const completeTime = performance.now();
            console.log(`⏱️ [KEYBOARD] Complete QR detected immediately! Time: ${completeTime.toFixed(2)}ms`);
            console.log(`⏰ [KEYBOARD] Complete QR at: ${new Date().toISOString()}`);
            
            const qrValue = keysRef.current.join("").substring(
              keysRef.current.indexOf("{"),
              keysRef.current.lastIndexOf("}") + 1
            );
            console.log(`⏱️ [KEYBOARD] QR value: ${qrValue}`);
            
            // ✅ TABLET OPTIMIZATION: Directly set qrCodeScannerValues without any state chain
            // Use flushSync for immediate update on tablets (if available, otherwise use regular setState)
            setQrCodeScannerValues((value) => {
              console.log(`⏱️ [KEYBOARD] Setting qrCodeScannerValues directly: ${qrValue}`);
              return [...value, qrValue];
            });
            
            // Reset scanner input immediately (using refs, no state update)
            keysRef.current = [];
            leftBraceCountRef.current = 0;
            rightBraceCountRef.current = 0;
            isFirstKeyRef.current = true;
            
            // ✅ TABLET OPTIMIZATION: Defer all cleanup state updates to avoid blocking
            // Use setTimeout to ensure QR processing happens first
            setTimeout(() => {
              startTransition(() => {
                setKeys([]);
                setLeftCurlyBraceCount(0);
                setRightCurlyBraceCount(0);
                setScanState("pending");
                resetScannerInput();
              });
            }, 0);
            
            return;
          }
        }
        
        // ✅ TABLET OPTIMIZATION: Completely skip state updates during scanning
        // Only update state for the first brace detection (for UI feedback)
        // All other updates are deferred to avoid blocking on tablets
        if (leftBraceCountRef.current === 1 && keysRef.current.length === 1 && event.key === "{") {
          // Only update state once when first brace is detected
          startTransition(() => {
            setKeys([...keysRef.current]);
            setLeftCurlyBraceCount(leftBraceCountRef.current);
            setRightCurlyBraceCount(rightBraceCountRef.current);
          });
        }
        // Skip all other state updates during scanning to maximize performance on tablets
      };
  
      document.addEventListener("keydown", handleKeyDown);
      const listenerRegisterTime = performance.now() - listenerRegisterStartTime;
      console.log(`⏱️ [KEYBOARD LISTENER] Listener registered in: ${listenerRegisterTime.toFixed(2)}ms`);
      console.log(`⏰ [KEYBOARD LISTENER] Listener ready at: ${new Date().toISOString()}`);
  
      return () => {
        console.log(`⏱️ [KEYBOARD LISTENER] Removing keyboard listener at: ${new Date().toISOString()}`);
        document.removeEventListener("keydown", handleKeyDown);
      };
    } else {
      console.log(`⏱️ [KEYBOARD LISTENER EFFECT] Scanner not active, skipping listener registration`);
    }
    
    const effectTime = performance.now() - effectStartTime;
    console.log(`⏱️ [KEYBOARD LISTENER EFFECT] Total effect time: ${effectTime.toFixed(2)}ms`);
  }, [isScanning]);

// ✅ OPTIMIZED: Simplify the QR scanner effect - it's now mainly for initial detection
useEffect(() => {
  const effectStartTime = performance.now();
  console.log(`⏱️ [QR SCANNER EFFECT] Triggered at: ${new Date().toISOString()}`);
  console.log(`⏱️ [QR SCANNER EFFECT] Keys count: ${keys.length}, leftBrace: ${leftCurlyBraceCount}, rightBrace: ${rightCurlyBraceCount}`);
  
  if (rightCurlyBraceCount > leftCurlyBraceCount || leftCurlyBraceCount > 1) {  // Prevent multiple scan
    setScanState("retry");
    setScanError("Too many scans at once");
    resetQrCodeScanner("Too many scans at once");
  } else {
    // Only show "scanning" state when first brace is detected
    if (leftCurlyBraceCount == 1 && keys.length == 1)
      {
        const scanDetectedTime = performance.now();
        setScanState("scanning");
        console.log(`%c Scan detected, waiting for inputs...`, "color:cyan");
        console.log(`⏱️ [QR SCANNER] Scan detected time: ${scanDetectedTime.toFixed(2)}ms`);
        console.log(`⏰ [QR SCANNER] Scan detected at: ${new Date().toISOString()}`);
      }
    // Note: Complete QR detection is now handled directly in handleKeyDown
    // This effect is mainly for UI feedback and error handling
  }
}, [keys, leftCurlyBraceCount, rightCurlyBraceCount]);
  
  useEffect(() => {
    if (qrCodeScannerValues.length > 0) {
      const processStartTime = performance.now();
      console.log(`⏱️ [QR SCANNER PROCESS] Processing qrCodeScannerValues at: ${new Date().toISOString()}`);
      console.log(`⏱️ [QR SCANNER PROCESS] Values count: ${qrCodeScannerValues.length}`);
      
      const scannedValues = qrCodeScannerValues[0];
      console.log(`%c Scanned Result: `, "color:cyan", scannedValues);
      console.log(`⏱️ [QR SCANNER PROCESS] Scanned value: ${scannedValues}`);
      console.log(`⏰ [QR SCANNER PROCESS] Processing at: ${new Date().toISOString()}`);
  
      if (scannedValues.substring(0, 8) == "{2fitest") {  // DEBUGGING
        // 先检查是否是 {2fiteste...} 或 {2fitestu...} 格式
        // 这些格式需要传递完整值给 processQrCode 处理
        if (scannedValues.length > 9) {
          const ninthChar = scannedValues.substring(8, 9);
          if (ninthChar === "e" || ninthChar === "u") {
            // {2fiteste数字} 或 {2fitestu任何内容} 格式
            console.log(`%c DEBUG: detected shortcut format: `, "color:pink", scannedValues);
            const debugValue = {
              value: scannedValues // 传递完整值，让 processQrCode 处理
            }
            setScanResult(debugValue);
            const processTime = performance.now() - processStartTime;
            console.log(`⏱️ [QR SCANNER PROCESS] Shortcut processing time: ${processTime.toFixed(2)}ms`);
            return;
          }
        }
        
        // 原有的 {2fitest数字} 格式（纯数字，向后兼容）
        const number = scannedValues.substring(8, scannedValues.length - 1);
        if (/^\d+$/.test(number)) { // Check if number contains only digits
          console.log(`%c DEBUG: detected ID: `, "color:pink", number);
          const debugValue = {
            value: number
          }
          setScanResult(debugValue);
          const processTime = performance.now() - processStartTime;
          console.log(`⏱️ [QR SCANNER PROCESS] ID processing time: ${processTime.toFixed(2)}ms`);
          return;
        } else {
          // 如果不是纯数字，传递完整值让 processQrCode 处理
          const debugValue = {
            value: scannedValues
          }
          setScanResult(debugValue);
          const processTime = performance.now() - processStartTime;
          console.log(`⏱️ [QR SCANNER PROCESS] Non-numeric processing time: ${processTime.toFixed(2)}ms`);
          return;
        }
      }
  
      try {
          const parseStartTime = performance.now();
          const data: QrCodeInfo = JSON.parse(scannedValues);
          const parseTime = performance.now() - parseStartTime;
          console.log(`%c Parsed scan data`, "color:green", data);
          console.log(`⏱️ [QR SCANNER PROCESS] JSON parse time: ${parseTime.toFixed(2)}ms`);
          
          const content = scannedValues.substring(1, scannedValues.length - 1);
          data.value = content;
          
          const setResultStartTime = performance.now();
          setScanResult(data);
          const setResultTime = performance.now() - setResultStartTime;
          console.log(`⏱️ [QR SCANNER PROCESS] setScanResult time: ${setResultTime.toFixed(2)}ms`);
          console.log(`⏰ [QR SCANNER PROCESS] setScanResult at: ${new Date().toISOString()}`);
  
          const processTime = performance.now() - processStartTime;
          console.log(`⏱️ [QR SCANNER PROCESS] Total processing time: ${processTime.toFixed(2)}ms`);
  
      } catch (error) {   // Rough match for other scanner input -- Pending Review
          console.log(`⏱️ [QR SCANNER PROCESS] JSON parse failed, trying rough match`);
          const silId = findIdByRoughMatch(scannedValues, "StockInLine").number ?? 0;
          
          if (silId == 0) {
            const whId = findIdByRoughMatch(scannedValues, "warehouseId").number ?? 0;
            setScanResult({...scanResult, stockInLineId: whId, value: whId.toString()});
          } else { setScanResult({...scanResult, stockInLineId: silId, value: silId.toString()}); }
  
          resetQrCodeScanner(String(error));
      }
  
    // resetQrCodeScanner();
    }
  }, [qrCodeScannerValues]);

  return (
    <QrCodeScannerContext.Provider
      value={{
        values: qrCodeScannerValues,
        isScanning: isScanning,
        startScan: startQrCodeScanner,
        stopScan: endQrCodeScanner,
        resetScan: resetQrCodeScanner,
        result: scanResult,
        state: scanState,
        error: scanError,
      }}
    >
      {children}
    </QrCodeScannerContext.Provider>
  );
};

export const useQrCodeScannerContext = (): QrCodeScanner => {
  const context = useContext(QrCodeScannerContext);
  if (!context) {
    throw new Error(
      "useQrCodeScanner must be used within a QrCodeScannerProvider",
    );
  }
  return context;
};

export default QrCodeScannerProvider;
