'use client';

import { useEffect, useRef, useState } from 'react';
import { Html5Qrcode, Html5QrcodeSupportedFormats } from 'html5-qrcode';
import CameraView from './CameraView';

interface ScannerProps {
  onScanSuccess: (decodedText: string) => void;
  onOCRMatch?: (text: string) => void;
  paused?: boolean;
}

export default function Scanner({ onScanSuccess, onOCRMatch, paused }: ScannerProps) {
  const html5QrCodeRef = useRef<Html5Qrcode | null>(null);
  const [isStarted, setIsStarted] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [ocrProcessing, setOcrProcessing] = useState(false);
  const [countdown, setCountdown] = useState(4);
  const [zoom, setZoom] = useState(1);
  const [maxZoom, setMaxZoom] = useState(1);
  const [hasZoom, setHasZoom] = useState(false);
  const [detectedWords, setDetectedWords] = useState<{ text: string, bbox: { x0: number, y0: number, x1: number, y1: number } }[]>([]);
  const [isSelecting, setIsSelecting] = useState(false);
  const [capturedImage, setCapturedImage] = useState<string | null>(null);
  const isBusy = useRef(false);
  const isTransitioning = useRef(false); // Flag to track start/stop transitions
  const scannerId = "reader-container-unique";

  useEffect(() => {
    if (!html5QrCodeRef.current) {
        html5QrCodeRef.current = new Html5Qrcode(scannerId);
    }

    const startScanner = async () => {
      if (isBusy.current || isTransitioning.current) return;
      isBusy.current = true;
      isTransitioning.current = true;

      try {
        // If already scanning, we MUST stop it first
        if (html5QrCodeRef.current?.isScanning) {
            try {
              await html5QrCodeRef.current.stop();
            } catch (e) {
              console.warn("Graceful stop failed, might be in transition:", e);
              // If it's already in transition, we just return and wait for the next effect trigger
              return;
            }
        }

        const config = { 
          fps: 15,
          qrbox: { width: 320, height: 320 },
          aspectRatio: 1.0,
          formatsToSupport: [
              Html5QrcodeSupportedFormats.QR_CODE,
              Html5QrcodeSupportedFormats.CODE_128,
              Html5QrcodeSupportedFormats.CODE_39,
              Html5QrcodeSupportedFormats.EAN_13,
              Html5QrcodeSupportedFormats.UPC_A,
              Html5QrcodeSupportedFormats.DATA_MATRIX
          ],
          videoConstraints: {
            facingMode: "environment"
          }
        };

        await html5QrCodeRef.current?.start(
          { facingMode: "environment" },
          config,
          (decodedText) => {
            onScanSuccess(decodedText);
          },
          () => {} // Ignore frame errors
        );

        const video = document.querySelector(`#${scannerId} video`) as HTMLVideoElement;
        const track = (video?.srcObject as MediaStream)?.getVideoTracks()[0];
        const caps = track?.getCapabilities() as any;
        if (track && caps?.zoom) {
          setHasZoom(true);
          setMaxZoom(caps.zoom.max || 3);
        }

        setIsStarted(true);
        setError(null);
      } catch (err: any) {
        const errorMsg = String(err);
        if (!errorMsg.includes("is already starting") && !errorMsg.includes("already under transition")) {
            console.error("Scanner failed", err);
            setError(errorMsg || "Failed to access camera");
            setIsStarted(false);
        }
      } finally {
        isBusy.current = false;
        isTransitioning.current = false;
      }
    };

    if (!paused) {
      startScanner();
    }

    return () => {
      if (html5QrCodeRef.current?.isScanning) {
        isTransitioning.current = true;
        html5QrCodeRef.current.stop()
            .then(() => {
                setIsStarted(false);
            })
            .catch(e => console.error("Unmount stop failed", e))
            .finally(() => {
                isTransitioning.current = false;
            });
      }
    };
  }, [paused, onScanSuccess]);

  // Automated OCR Countdown Timer
  useEffect(() => {
    if (!isStarted || paused || isSelecting || ocrProcessing) {
      return;
    }

    const timer = setInterval(() => {
      setCountdown(prev => {
        if (prev <= 1) {
          handleOCR();
          return 4; // Reset to 4
        }
        return prev - 1;
      });
    }, 1000);

    return () => clearInterval(timer);
  }, [isStarted, paused, isSelecting, ocrProcessing]);

  const handleOCR = async () => {
    if (ocrProcessing) return;
    setOcrProcessing(true);
    try {
      const video = document.querySelector(`#${scannerId} video`) as HTMLVideoElement;
      if (!video) return;

      const canvas = document.createElement('canvas');
      const vWidth = video.videoWidth || 1280;
      const vHeight = video.videoHeight || 720;
      
      const cropFactor = 0.6;
      const sw = vWidth * cropFactor;
      const sh = vHeight * cropFactor;
      const sx = (vWidth - sw) / 2;
      const sy = (vHeight - sh) / 2;

      canvas.width = 1200; 
      canvas.height = (sh / sw) * 1200;
      
      const ctx = canvas.getContext('2d');
      if (ctx) {
        ctx.filter = 'grayscale(100%) contrast(180%) brightness(105%)';
        ctx.drawImage(video, sx, sy, sw, sh, 0, 0, canvas.width, canvas.height);
      }

      // Lazy-load tesseract.js only when OCR is actually needed
      const { createWorker } = await import('tesseract.js');
      const workerPromise = createWorker('eng');
      const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error("OCR Engine timeout")), 20000));

      const worker = await Promise.race([workerPromise, timeoutPromise]) as any;
      const dataUrl = canvas.toDataURL('image/jpeg', 0.85);
      
      setCapturedImage(dataUrl);

      const result = await worker.recognize(dataUrl);
      const data = result.data;
      
      if (data && data.text && (!data.words || data.words.length === 0)) {
         onOCRMatch?.(data.text);
         await worker.terminate();
         setCapturedImage(null);
         return;
      }

      if (!data || !data.words || data.words.length === 0) {
         await worker.terminate();
         setCapturedImage(null);
         return;
      }

      const words = data.words.map((w: any) => ({
        text: w.text,
        bbox: w.bbox
      }));

      setDetectedWords(words);
      setIsSelecting(true);
      await worker.terminate();
    } catch (err) {
      console.error("OCR failed", err);
    } finally {
      setOcrProcessing(false);
    }
  };

  const handleWordSelect = (text: string) => {
    onOCRMatch?.(text);
    setIsSelecting(false);
    setCapturedImage(null);
    setDetectedWords([]);
    setCountdown(4); // Restart countdown
  };

  const handleCancelSelection = () => {
    setIsSelecting(false);
    setCapturedImage(null);
    setCountdown(4);
  };

  const handleZoomChange = async (nextZoom: number) => {
    const video = document.querySelector(`#${scannerId} video`) as HTMLVideoElement;
    const track = (video?.srcObject as MediaStream)?.getVideoTracks()[0];
    if (track) {
      await track.applyConstraints({ advanced: [{ zoom: nextZoom }] as any });
      setZoom(nextZoom);
    }
  };

  return (
    <CameraView
      scannerId={scannerId}
      isStarted={isStarted}
      paused={paused}
      error={error}
      hasZoom={hasZoom}
      zoom={zoom}
      maxZoom={maxZoom}
      onZoomChange={handleZoomChange}
      countdown={countdown}
      ocrProcessing={ocrProcessing}
      isSelecting={isSelecting}
      capturedImage={capturedImage}
      detectedWords={detectedWords}
      onWordSelect={handleWordSelect}
      onCancelSelection={handleCancelSelection}
    />
  );
}
