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

export interface QrCodeScanner {
  values: string[];
  isScanning: boolean;
  startScan: () => void;
  stopScan: () => void;
  resetScan: () => void;
  result: QrCodeInfo | 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 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);
    }
  }, []);

  const startQrCodeScanner = useCallback(() => {
    resetQrCodeScanner();
    setIsScanning(() => true);
    console.log("%c Scanning started ", "color:cyan");
  }, []);

  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;
  };

  // Check the KeyDown
  useEffect(() => {
    if (isScanning) {
      const handleKeyDown = (event: KeyboardEvent) => {
        if (event.key.length === 1) {
          setKeys((key) => [...key, event.key]);
        }

        if (event.key === "{") {
          setLeftCurlyBraceCount((count) => count + 1);
        } else if (event.key === "}") {
          setRightCurlyBraceCount((count) => count + 1);
        }
      };

      document.addEventListener("keydown", handleKeyDown);

      return () => {
        document.removeEventListener("keydown", handleKeyDown);
      };
    }
  }, [isScanning]);

  // Update Qr Code Scanner Values
  useEffect(() => {
    if (rightCurlyBraceCount > leftCurlyBraceCount || leftCurlyBraceCount > 1) {  // Prevent multiple scan
      resetQrCodeScanner("Too many scans at once");
    } else {
      if (leftCurlyBraceCount == 1 && keys.length == 1)
        { console.log("%c Scan detected, waiting for inputs...", "color:cyan"); }
      if (
        leftCurlyBraceCount !== 0 &&
        rightCurlyBraceCount !== 0 &&
        leftCurlyBraceCount === rightCurlyBraceCount
      ) {
        const startBrace = keys.indexOf("{");
        const endBrace = keys.lastIndexOf("}");
        setQrCodeScannerValues((value) => [
          ...value,
          keys.join("").substring(startBrace, endBrace + 1),
        ]);
        // console.log(keys);
        // console.log("%c QR Scanner Values:", "color:cyan", qrCodeScannerValues);
  
        resetScannerInput();
      }
    }
  }, [keys, leftCurlyBraceCount, rightCurlyBraceCount]);

  useEffect(() => {
    if (qrCodeScannerValues.length > 0) {
      const scannedValues = qrCodeScannerValues[0];
      console.log("%c Scanned Result: ", "color:cyan", scannedValues);

      if (scannedValues.substring(0, 8) == "{2fitest") {  // DEBUGGING
          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);
          } else {
            resetQrCodeScanner("DEBUG -- Invalid number format: " + number);
          }
          return;
      }

      try {
          const data: QrCodeInfo = JSON.parse(scannedValues);
          console.log("%c Parsed scan data", "color:green", data);
          
          const content = scannedValues.substring(1, scannedValues.length - 1);
          data.value = content;
          setScanResult(data);

      } catch (error) {   // Rought match for other scanner input -- Pending Review
          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,
      }}
    >
      {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;
