// import React, { useState, useEffect, useRef } from 'react';
// import './App.css';

// const App = () => {
//   const [opencvLoaded, setOpencvLoaded] = useState(false);
//   const [isCanvasVisible, setIsCanvasVisible] = useState(false);
//   const videoRef = useRef(null);
//   const canvasRef = useRef(null);
//   const instructionTextRef = useRef(null);
//   const loaderRef = useRef(null);
//   const FPS = 1080;
//   const ZOOM_FACTOR = 1.5;

//   useEffect(() => {
//     const checkOpenCV = () => {
//       if (window.cv) {
//         setOpencvLoaded(true);
//       } else {
//         setTimeout(checkOpenCV, 100);
//       }
//     };
//     checkOpenCV();
//   }, []);

//   useEffect(() => {
//     if (opencvLoaded) {
//       openCvReady();
//     }
//   }, [opencvLoaded]);

//   const openCvReady = () => {
//     console.log("in opencvready");
//     window.cv['onRuntimeInitialized'] = () => {
//       const video = videoRef.current;
//       const canvas = canvasRef.current;
//       const instructionText = instructionTextRef.current;
//       navigator.mediaDevices.getUserMedia({
//         video: true,
//         audio: false
//       })
//         .then(function (stream) {
//           video.srcObject = stream;
//           video.play();
//           setIsCanvasVisible(false);

//           const videoAspect = video.videoWidth / video.videoHeight;
//           const canvasWidth = canvas.clientWidth;
//           const canvasHeight = canvasWidth / videoAspect;

//           canvas.width = canvasWidth;
//           canvas.height = canvasHeight;
//         })
//         .catch(function (err) {
//           console.log("An error occurred! " + err);
//         });

//       let src = new window.cv.Mat(video.height, video.width, window.cv.CV_8UC4);
//       let dst = new window.cv.Mat(video.height, video.width, window.cv.CV_8UC4);
//       let gray = new window.cv.Mat();
//       let cap = new window.cv.VideoCapture(video);
//       let faces = new window.cv.RectVector();
//       let classifier = new window.cv.CascadeClassifier();
//       const utils = new window.Utils('errorMessage');
//       const faceCascadeFile = 'haarcascade_frontalface_default.xml';
//       utils.createFileFromUrl(faceCascadeFile, faceCascadeFile, () => {
//       //  classifier.load(faceCascadeFile);


//      classifier.load(faceCascadeFile); // Ensure the path is correct
//      console.log("Classifier loaded:", classifier.empty() ? "Failed to load" : "Successfully loaded");

//       });

//       const processVideo = () => {

//         if (!window.cv || !window.cv.Mat) {
//           console.log('OpenCV.js is not loaded');
//           return;
//         }else{
//           console.log('OpenCV.js is loaded');
//         }
        

//         let begin = Date.now();
//         cap.read(src);
//         console.log("process video 1");
//         // Zoom the video frame
//         let zoomedSrc = new window.cv.Mat();
//         let zoomRect = new window.cv.Rect(
//           src.cols / 2 - (src.cols / (2 * ZOOM_FACTOR)),
//           src.rows / 2 - (src.rows / (2 * ZOOM_FACTOR)),
//           src.cols / ZOOM_FACTOR,
//           src.rows / ZOOM_FACTOR
//         );
//         zoomedSrc = src.roi(zoomRect);
//         window.cv.resize(zoomedSrc, dst, new window.cv.Size(src.cols, src.rows), 0, 0, window.cv.INTER_LINEAR);
//         console.log("process video 2");
//         let clonedst = new window.cv.Mat();
//         dst.copyTo(clonedst);

//         instructionText.textContent = "Keep Your Face In fThe Frame";
//         console.log("process video 3");
//         // Perform face detection on the zoomed image
//         let faces1 = new window.cv.RectVector();
//         console.log("process video 3.1");
//         let faces = new window.cv.RectVector();
//         console.log("process video 3.2");
//        // try {

//         //  window.cv.imshow("canvas_output",src);
       

//           console.log("process video 3.3");
//         //  classifier.detectMultiScale(src, faces, 1.5, 3, 0);
//           classifier.detectMultiScale(src, faces, 1.5, 3,0,);

//           console.log("process video 3.4");
//           classifier.detectMultiScale(src, faces1, 1.5, 3, 0);
//           console.log("process video 4");
//           console.log("Face size is " + faces.size() + faces1.size());
//           console.log("process video 5");
//           if (faces1.size() === 1) {
//             const face = faces.get(0);
//             const face1 = faces1.get(0);
//             const rect = new window.cv.Rect(face.x, face.y, face.width, face.height);
//             console.log("process video 6");
//             const bufferRatio = 0.14; // 18% buffer
//             let bufferedX = Math.max(0, face.x - face.width * bufferRatio);
//             let bufferedY = Math.max(0, face.y - face.height * bufferRatio);
//             let bufferedWidth = Math.min(src.cols - bufferedX, face.width * (1 + 2 * bufferRatio));
//             let bufferedHeight = Math.min(src.rows - bufferedY, face.height * (1 + 2 * bufferRatio));
//             console.log("process video 7");
//             const bufferedRect = new window.cv.Rect(bufferedX, bufferedY, bufferedWidth, bufferedHeight);
//             console.log("process video 8");
//             // Draw the buffered rectangle on the canvas
//             window.cv.rectangle(src, new window.cv.Point(bufferedRect.x, bufferedRect.y), new window.cv.Point(bufferedRect.x + bufferedRect.width, bufferedRect.y + bufferedRect.height), [5, 255, 0, 255], 2);
//             console.log("process video 9");
//             const faceArea = face1.width * face1.height;
//             const ovalArea = Math.PI * (canvas.width / 2) * (canvas.height / 2);
//             const faceAreaPercentage = (faceArea / ovalArea) * 100;
//             let faceDetectionCount = 0;
//             console.log("process video 10");
//             if (!isFaceInsideOval(face1, canvas)) {
//               instructionText.textContent = "Move inside the oval window";
//               faceDetectionCount = 0;
//             } else if (faceAreaPercentage < 40) {
//               instructionText.textContent = "Stay closer to the window";
//               faceDetectionCount = 0;
//             } else if (faceAreaPercentage >= 40 && faceAreaPercentage <= 100) {
//               instructionText.textContent = "Processing....";
//               faceDetectionCount++;
//               if (faceDetectionCount === 3) {
//                 uploadBufferedFaceImage(bufferedRect);
//                 showLoader();
//                 return false;
//               }
//             }
//           }
//     //    } catch (err) {
//     //      console.log(err);
//      //   } finally {
//      //    faces1.delete();
//       //  }

//         // Show the result on the canvas
//         if (isCanvasVisible) {
//           window.cv.flip(dst, dst, 1);
//          // window.cv.imshow("canvas_output", dst);
//         }

//         let delay = 1000 / FPS - (Date.now() - begin);
//         setTimeout(processVideo, delay);
//       };

//       const uploadBufferedFaceImage = (rect) => {
//         const videoCanvas = document.createElement('canvas');
//         videoCanvas.width = video.videoWidth;
//         videoCanvas.height = video.videoHeight;
//         const videoCtx = videoCanvas.getContext('2d');
//         videoCtx.drawImage(video, 0, 0, videoCanvas.width, videoCanvas.height);

//         const cropCanvas = document.createElement('canvas');
//         cropCanvas.width = rect.width;
//         cropCanvas.height = rect.height;
//         const cropCtx = cropCanvas.getContext('2d');

//         const imageData = videoCtx.getImageData(rect.x, rect.y, rect.width, rect.height);
//         cropCtx.putImageData(imageData, 0, 0);

//         cropCanvas.toBlob((blob) => {
//           const formData = new FormData();
//           formData.append('image', blob, 'buffered_face_image.jpg');

//           fetch('http://192.168.1.57:8012/upload.php', {
//             method: 'POST',
//             body: formData
//           })
//             .then(response => response.json())
//             .then(data => {
//               if (data.error) {
//                 alert('Please try again. Something went wrong.');
//                 console.log(data);
//                 window.location.reload();
//               } else {
//                 console.log('Image uploaded successfully');
//                 const score = data.score;
//                 if (score >= 50) {
//                   window.location.href = 'verified.html';
//                 } else {
//                   window.location.href = 'failed.html';
//                 }
//               }
//             })
//             .catch(error => {
//               console.error('Error uploading image:', error);
//               alert('Please try again. Something went wrong.');
//               window.location.reload();
//             });

//           // const downloadLink = document.createElement('a');
//           // downloadLink.href = URL.createObjectURL(blob);
//           // downloadLink.download = 'buffered_face_image.jpg';
//           // downloadLink.style.display = 'none';
//           // document.body.appendChild(downloadLink);
//           // downloadLink.click();
//           // document.body.removeChild(downloadLink);
//         }, 'image/jpeg', 0.92);
//       };

//       setTimeout(processVideo, 0);
//     };
//   };

//   const showLoader = () => {
//     loaderRef.current.style.display = 'block';
//   };

//   const isFaceInsideOval = (face, canvas) => {
//     const ovalCenterX = canvas.width / 2;
//     const ovalCenterY = canvas.height / 2;
//     const ovalRadiusX = canvas.width / 2;
//     const ovalRadiusY = canvas.height / 2;

//     const faceCenterX = face.x + face.width / 2;
//     const faceCenterY = face.y + face.height / 2;

//     const dx = Math.abs(faceCenterX - ovalCenterX) / ovalRadiusX;
//     const dy = Math.abs(faceCenterY - ovalCenterY) / ovalRadiusY;

//     return dx * dx + dy * dy <= 1;
//   };

//   return (
//     <div className="App">
//       <div className="loader" ref={loaderRef}></div>
//       <div id="content">
//         <div className="instruction-box">
//           <p className="instruction-text" ref={instructionTextRef}>Please position your face inside the oval window and ensure sufficient lighting.</p>
//         </div>
//         <div className="camera-container">
//           <video id="camera_input" ref={videoRef} className="camera-input" width="1080" height="720"></video>
//           <canvas id="canvas_output" ref={canvasRef} className="camera-output"></canvas>
//         </div>
//       </div>
//     </div>
//   );
// };

// export default App;









import React, { useState, useEffect, useRef } from 'react';
import './App.css';

const App = () => {
  const [opencvLoaded, setOpencvLoaded] = useState(false);
  const [isCanvasVisible, setIsCanvasVisible] = useState(false);
  const videoRef = useRef(null);
  const canvasRef = useRef(null);
  const instructionTextRef = useRef(null);
  const loaderRef = useRef(null);
  const FPS = 30; // Adjust FPS as needed
  const ZOOM_FACTOR = 1.5;

  useEffect(() => {
    const checkOpenCV = () => {
      if (window.cv) {
        setOpencvLoaded(true);
      } else {
        setTimeout(checkOpenCV, 100);
      }
    };
    checkOpenCV();
  }, []);

  useEffect(() => {
    if (opencvLoaded) {
      openCvReady();
    }
  }, [opencvLoaded]);

  const openCvReady = () => {
    console.log("in opencvready");
    window.cv['onRuntimeInitialized'] = () => {
      const video = videoRef.current;
      const canvas = canvasRef.current;
      const instructionText = instructionTextRef.current;
      navigator.mediaDevices.getUserMedia({
        video: true,
        audio: false
      })
        .then(function (stream) {
          video.srcObject = stream;
          video.play();
          setIsCanvasVisible(false);

          video.addEventListener('loadeddata', () => {
            const videoAspect = video.videoWidth / video.videoHeight;
            const canvasWidth = canvas.clientWidth;
            const canvasHeight = canvasWidth / videoAspect;

            canvas.width = canvasWidth;
            canvas.height = canvasHeight;

            const src = new window.cv.Mat(video.videoHeight, video.videoWidth, window.cv.CV_8UC4);
            const dst = new window.cv.Mat(video.videoHeight, video.videoWidth, window.cv.CV_8UC4);
            const gray = new window.cv.Mat();
            const cap = new window.cv.VideoCapture(video);
            const faces = new window.cv.RectVector();
            const classifier = new window.cv.CascadeClassifier();
            const utils = new window.Utils('errorMessage');
            const faceCascadeFile = 'haarcascade_frontalface_default.xml';
            utils.createFileFromUrl(faceCascadeFile, faceCascadeFile, () => {
              classifier.load(faceCascadeFile);
              console.log("Classifier loaded:", classifier.empty() ? "Failed to load" : "Successfully loaded");
            });

            const processVideo = () => {
              if (!window.cv || !window.cv.Mat) {
                console.log('OpenCV.js is not loaded');
                return;
              } else {
                console.log('OpenCV.js is loaded');
              }

              let begin = Date.now();
              cap.read(src);
              console.log("process video 1");

              // Zoom the video frame
              let zoomedSrc = new window.cv.Mat();
              let zoomRect = new window.cv.Rect(
                src.cols / 2 - (src.cols / (2 * ZOOM_FACTOR)),
                src.rows / 2 - (src.rows / (2 * ZOOM_FACTOR)),
                src.cols / ZOOM_FACTOR,
                src.rows / ZOOM_FACTOR
              );
              zoomedSrc = src.roi(zoomRect);
              window.cv.resize(zoomedSrc, dst, new window.cv.Size(src.cols, src.rows), 0, 0, window.cv.INTER_LINEAR);
              console.log("process video 2");
              let clonedst = new window.cv.Mat();
              dst.copyTo(clonedst);

              instructionText.textContent = "Keep Your Face In The Frame";
              console.log("process video 3");
              // Perform face detection on the zoomed image
              let faces1 = new window.cv.RectVector();
              console.log("process video 3.1");
              let faces = new window.cv.RectVector();
              console.log("process video 3.2");
              try {
                console.log("process video 3.3");
                classifier.detectMultiScale(src, faces, 1.5, 3, 0);
                console.log("process video 3.4");
                classifier.detectMultiScale(src, faces1, 1.5, 3, 0);
                console.log("process video 4");
                console.log("Face size is " + faces.size() + faces1.size());
                console.log("process video 5");
                console.log("faces1.size: ",faces1.size());
                if (faces1.size() === 1) {
                  const face = faces.get(0);
                  const face1 = faces1.get(0);
                  const rect = new window.cv.Rect(face.x, face.y, face.width, face.height);
                  console.log("process video 6");
                  const bufferRatio = 0.14; // 14% buffer
                  let bufferedX = Math.max(0, face.x - face.width * bufferRatio);
                  let bufferedY = Math.max(0, face.y - face.height * bufferRatio);
                  let bufferedWidth = Math.min(src.cols - bufferedX, face.width * (1 + 2 * bufferRatio));
                  let bufferedHeight = Math.min(src.rows - bufferedY, face.height * (1 + 2 * bufferRatio));
                  console.log("process video 7");
                  const bufferedRect = new window.cv.Rect(bufferedX, bufferedY, bufferedWidth, bufferedHeight);
                  console.log("process video 8");
                  // Draw the buffered rectangle on the canvas
                  window.cv.rectangle(src, new window.cv.Point(bufferedRect.x, bufferedRect.y), new window.cv.Point(bufferedRect.x + bufferedRect.width, bufferedRect.y + bufferedRect.height), [5, 255, 0, 255], 2);
                  console.log("process video 9");
                  const faceArea = face1.width * face1.height;
                  const ovalArea = Math.PI * (canvas.width / 2) * (canvas.height / 2);
                  const faceAreaPercentage = (faceArea / ovalArea) * 100;
                  let faceDetectionCount = 0;
                  console.log("process video 10");
                  if (!isFaceInsideOval(face1, canvas)) {
                    console.log("in is faceinsideoval if");
                    instructionText.textContent = "Move inside the oval window";
                    faceDetectionCount = 0;
                  } else if (faceAreaPercentage < 40) {
                    instructionText.textContent = "Stay closer to the window";
                    faceDetectionCount = 0;
                  } else if (faceAreaPercentage >= 40 && faceAreaPercentage <= 100) {
                    instructionText.textContent = "Processing....";
                    faceDetectionCount++;
                    if (faceDetectionCount === 3) {
                      uploadBufferedFaceImage(bufferedRect);
                      showLoader();
                      return false;
                    }
                  }
                }
              } catch (err) {
                console.log(err);
              } finally {
                faces1.delete();
                faces.delete();
              }

              // Show the result on the canvas
              if (isCanvasVisible) {
                window.cv.flip(dst, dst, 1);
                window.cv.imshow("canvas_output", dst);
              }

              let delay = 1000 / FPS - (Date.now() - begin);
              setTimeout(processVideo, delay);
            };

            const uploadBufferedFaceImage = (rect) => {
              const videoCanvas = document.createElement('canvas');
              videoCanvas.width = video.videoWidth;
              videoCanvas.height = video.videoHeight;
              const videoCtx = videoCanvas.getContext('2d');
              videoCtx.drawImage(video, 0, 0, videoCanvas.width, videoCanvas.height);

              const cropCanvas = document.createElement('canvas');
              cropCanvas.width = rect.width;
              cropCanvas.height = rect.height;
              const cropCtx = cropCanvas.getContext('2d');

              const imageData = videoCtx.getImageData(rect.x, rect.y, rect.width, rect.height);
              cropCtx.putImageData(imageData, 0, 0);

              cropCanvas.toBlob((blob) => {
                const formData = new FormData();
                formData.append('image', blob, 'buffered_face_image.jpg');

                fetch('http://192.168.1.57:8012/upload.php', {
                  method: 'POST',
                  body: formData
                })
                  .then(response => response.json())
                  .then(data => {
                    if (data.error) {
                      alert('Please try again. Something went wrong.');
                      console.log(data);
                      window.location.reload();
                    } else {
                      console.log('Image uploaded successfully');
                      const score = data.score;
                      if (score >= 50) {
                        window.location.href = 'verified.html';
                      } else {
                        window.location.href = 'failed.html';
                      }
                    }
                  })
                  .catch(error => {
                    console.error('Error uploading image:', error);
                    alert('Please try again. Something went wrong.');
                    window.location.reload();
                  });
              }, 'image/jpeg', 0.92);
            };

            setTimeout(processVideo, 0);
          });
        })
        .catch(function (err) {
          console.log("An error occurred! " + err);
        });
    };
  };

  const showLoader = () => {
    loaderRef.current.style.display = 'block';
  };

  const isFaceInsideOval = (face, canvas) => {
    const ovalCenterX = canvas.width / 2;
    const ovalCenterY = canvas.height / 2;
    const ovalRadiusX = canvas.width / 2;
    const ovalRadiusY = canvas.height / 2;

    const faceCenterX = face.x + face.width / 2;
    const faceCenterY = face.y + face.height / 2;

    const distanceX = (faceCenterX - ovalCenterX) ** 2 / (ovalRadiusX ** 2);
    const distanceY = (faceCenterY - ovalCenterY) ** 2 / (ovalRadiusY ** 2);
    console.log("isFaceInsideOvalfunctionend");
    return distanceX + distanceY <= 1;
  };

  return (
    <div className="container">
      <h1 className="title">Face Detection App</h1>
      <div className="camera-input">
        <video id="videoInput" ref={videoRef} width="640" height="480" autoPlay muted></video>
        <canvas id="canvasOutput" ref={canvasRef} style={{ display: isCanvasVisible ? 'block' : 'none' }}></canvas>
        <canvas id="canvas_output" width="640" height="480"></canvas>
      
      </div>
      <div id="loader" ref={loaderRef} className="loader" style={{ display: 'none' }}></div>
      <p className="status-text">Status: {opencvLoaded ? "OpenCV.js loaded" : "Loading OpenCV.js..."}</p>
      <p className="powered-by">Powered by OpenCV.js</p>
      <p id="instructionText" ref={instructionTextRef}></p>
    </div>
  );
};

export default App;



