import React, { useState, useRef, useEffect } from 'react';
import * as faceapi from 'face-api.js';
import { 
  sendImageForLiveness, 
  sendImageForIdentityComparison, 
  LivenessResponse, 
  IdentityComparisonResponse 
} from '../utils/api';

import './IdentityComparisonPopup.css';

/**
 * Interface for ID type options
 */
export interface IdType {
  /** Value to be sent to the API */
  value: string;
  /** Display label for the dropdown */
  label: string;
}

/**
 * Props for the IdentityComparisonPopup component
 */
export interface IdentityComparisonPopupProps {
  /** API key for authentication */
  apiKey: string;
  /** The name of your application */
  name: string;
  /** The URL for the identity comparison API endpoint */
  apiUrl: string;
  /** Callback function called when the popup is closed */
  onClose: () => void;
  /** Callback function called with the result of the identity comparison */
  onIdentityComparisonResult: (result: IdentityComparisonResponse) => void;
  /** Path to the face-api.js models (optional) */
  modelPath?: string;
  /** Array of ID types to display in the dropdown (optional) */
  idTypes?: IdType[];
}

// Default ID types
const DEFAULT_ID_TYPES: IdType[] = [
  { value: 'BVN', label: 'BVN' },
  { value: 'PHONENUMBER', label: 'Phone Number' },
  { value: 'FRSC', label: 'FRSC' },
  { value: 'NIN', label: 'NIN' }
];

/**
 * Identity Comparison Popup Component
 * 
 * A React component that provides a UI for identity verification using liveness checks
 * and ID verification.
 */
const IdentityComparisonPopup: React.FC<IdentityComparisonPopupProps> = ({
  apiKey,
  name,
  apiUrl,
  onClose,
  onIdentityComparisonResult,
  modelPath,
  idTypes = DEFAULT_ID_TYPES,
}) => {
  // State management
  const [currentStep, setCurrentStep] = useState<number>(1);
  const [consentGiven, setConsentGiven] = useState<boolean>(false);
  const [selectedIdType, setSelectedIdType] = useState<string>('');
  const [idNumber, setIdNumber] = useState<string>('');
  const [showCamera, setShowCamera] = useState<boolean>(false);
  const [message, setMessage] = useState<string>('');
  const [isError, setIsError] = useState<boolean>(false);
  const [isSuccess, setIsSuccess] = useState<boolean>(false);
  const [faceDetected, setFaceDetected] = useState<boolean>(false);
  const [processing, setProcessing] = useState<boolean>(false);
  const [identityProcessing, setIdentityProcessing] = useState<boolean>(false);
  const [showRetry, setShowRetry] = useState<boolean>(false);
  const [identityComparisonResult, setIdentityComparisonResult] = useState<IdentityComparisonResponse | null>(null);
  const [modelsLoaded, setModelsLoaded] = useState<boolean>(false);

  // Refs
  const videoRef = useRef<HTMLVideoElement>(null);
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const streamRef = useRef<MediaStream | null>(null);
  const detectionIntervalRef = useRef<number | null>(null);

  // Load face-api.js models
  useEffect(() => {
    const loadModels = async () => {
      try {
        console.log('Loading face-api.js models from:', modelPath);
        
        await Promise.all([
          faceapi.nets.tinyFaceDetector.loadFromUri(modelPath),
          faceapi.nets.faceLandmark68Net.loadFromUri(modelPath)
        ]);
        
        console.log('Face-api.js models loaded successfully');
        setModelsLoaded(true);
    } catch (error) {
        console.error('Error loading face-api.js models:', error);
        setMessage('Error loading face detection models. Please check console for details.');
      setIsError(true);
    }
  };

    loadModels();

    // Cleanup function
    return () => {
      if (streamRef.current) {
        streamRef.current.getTracks().forEach(track => track.stop());
      }
      if (detectionIntervalRef.current) {
        window.clearInterval(detectionIntervalRef.current);
      }
    };
  }, [modelPath]);

  // Setup camera and face detection
  const setupCamera = async () => {
    try {
      if (!videoRef.current) {
        console.error('Video ref not available');
        setTimeout(() => {
          if (videoRef.current) {
            setupCamera();
          }
        }, 500);
        return;
      }

      console.log('Requesting camera access...');
      
      const stream = await navigator.mediaDevices.getUserMedia({
        video: true,
        audio: false
      });
      
      console.log('Camera access granted');
      
      videoRef.current.srcObject = stream;
      streamRef.current = stream;
      
      videoRef.current.onloadedmetadata = () => {
      if (videoRef.current) {
          videoRef.current.play()
            .then(() => {
              console.log('Video playback started');
              startFaceDetection();
            })
            .catch(err => {
              console.error('Error playing video:', err);
            });
        }
      };
      
      setMessage('Position your face in the frame');
    } catch (error) {
      console.error('Error accessing camera:', error);
      setMessage('Unable to access the camera. Please ensure you have given permission.');
      setIsError(true);
    }
  };

  // Start face detection interval
  const startFaceDetection = () => {
    if (!videoRef.current || !canvasRef.current) {
      console.error('Video or canvas ref not available');
      return;
    }

    if (videoRef.current.readyState !== 4) {
      console.log('Video not ready yet, waiting...');
      setTimeout(startFaceDetection, 100);
      return;
    }

    console.log('Starting face detection');
    
    const canvas = canvasRef.current;
    const video = videoRef.current;
    
    canvas.width = video.videoWidth;
    canvas.height = video.videoHeight;
    
    const displaySize = { 
      width: video.videoWidth, 
      height: video.videoHeight 
    };
    
    faceapi.matchDimensions(canvas, displaySize);

    detectionIntervalRef.current = window.setInterval(async () => {
      if (!videoRef.current) return;
      
        try {
          const detections = await faceapi.detectAllFaces(
            videoRef.current,
            new faceapi.TinyFaceDetectorOptions()
          ).withFaceLandmarks();

        const ctx = canvas.getContext('2d');
        if (!ctx) return;
        
        ctx.clearRect(0, 0, canvas.width, canvas.height);
          
          if (detections.length > 0) {
            const resizedDetections = faceapi.resizeResults(detections, displaySize);
          faceapi.draw.drawDetections(canvas, resizedDetections);
              faceapi.draw.drawFaceLandmarks(canvas, resizedDetections);
          setFaceDetected(true);
          setMessage('Face detected. Click "Capture Photo" when ready.');
          } else {
            setFaceDetected(false);
            setMessage('No face detected. Please position your face in the frame.');
        }
      } catch (err) {
        console.error('Error in face detection:', err);
      }
    }, 100);
  };

  // Navigate to next step
  const nextStep = () => {
    if (currentStep === 1 && !consentGiven) {
      return;
    }

    if (currentStep === 2 && (!selectedIdType || !idNumber)) {
      return;
    }

    setIsError(false);
    setMessage('');
    
    if (currentStep === 2) {
      setShowCamera(false); // Don't show camera immediately, show the start camera button first
    }
    
    setCurrentStep(currentStep + 1);
  };

  // Go back to previous step
  const goBack = () => {
    setIsError(false);
    setMessage('');
    
    if (currentStep === 3) {
      setShowCamera(false);
      if (streamRef.current) {
        streamRef.current.getTracks().forEach(track => track.stop());
      }
      if (detectionIntervalRef.current) {
        window.clearInterval(detectionIntervalRef.current);
      }
    }
    
    setCurrentStep(currentStep - 1);
  };

  // Close the popup
  const closePopup = () => {
    // Stop camera if active
    if (streamRef.current) {
      streamRef.current.getTracks().forEach(track => track.stop());
    }
    
    // Clear any intervals
    if (detectionIntervalRef.current) {
      window.clearInterval(detectionIntervalRef.current);
    }
    
    onClose();
  };

  // Start camera
  const startCamera = () => {
    if (!modelsLoaded) {
      setMessage('Face detection models are still loading. Please wait...');
      return;
    }
    
    setShowCamera(true);
    setupCamera();
  };

  // Capture photo for liveness check
  const capturePhoto = async () => {
    if (!videoRef.current || !faceDetected) {
      setMessage('No face detected. Please position your face in the frame.');
      setIsError(true);
      return;
    }
    
    clearInterval(detectionIntervalRef.current as number);
    setProcessing(true);
    setMessage('Processing image...');
    
    try {
      // Create a canvas to capture the photo
      const canvas = document.createElement('canvas');
      canvas.width = videoRef.current.videoWidth;
      canvas.height = videoRef.current.videoHeight;
      
      const ctx = canvas.getContext('2d');
      if (ctx) {
        ctx.drawImage(videoRef.current, 0, 0, canvas.width, canvas.height);
        
        // Convert to base64
        const photoData = canvas.toDataURL('image/png');
        
        // Send for liveness check
        setMessage('Performing liveness check...');
        
        const livenessResponse = await sendImageForLiveness(apiUrl, apiKey, photoData);
        
        if (livenessResponse.isLive) {
          setMessage('Liveness check successful. Proceeding with identity comparison...');
          setIdentityProcessing(true);
          
          try {
            // Send for identity comparison
            const identityResponse = await sendImageForIdentityComparison(
              apiUrl, 
              apiKey, 
              photoData, 
              selectedIdType, 
              idNumber
            );
            
            setIdentityComparisonResult(identityResponse);
            setIsSuccess(true);
            setCurrentStep(4); // Move to results step
            onIdentityComparisonResult(identityResponse);
          } catch (identityError) {
            console.error('Error during identity comparison:', identityError);
            setMessage((identityError as Error).message || 'Failed to complete identity comparison. Please try again.');
            setIsError(true);
            setShowRetry(true);
          } finally {
            setIdentityProcessing(false);
            setProcessing(false);
          }
        } else {
          // Handle failed liveness check with a specific message
          console.log('Liveness check failed with message:', livenessResponse.message);
          setMessage(livenessResponse.message || 'Liveness check failed. Please try again with better lighting and ensure your face is clearly visible.');
          setIsError(true);
          setShowRetry(true);
          setProcessing(false);
        }
      }
    } catch (error) {
      console.error('Error during verification:', error);
      setMessage((error as Error).message || 'Failed to process the image. Please try again.');
      setIsError(true);
      setShowRetry(true);
      setProcessing(false);
      setIdentityProcessing(false);
    }
  };

  // Retry the verification process
  const retryCapture = () => {
    setShowRetry(false);
    setShowCamera(true);
    setFaceDetected(false);
    setMessage('');
    setIsError(false);
    startCamera();
  };

  return (
    <div className="dikriptLivenessPopup">
      <div className="dikriptPopupContent">
        <div className="dikriptHeader">
          {currentStep > 1 && 
            <button className="dikriptBackButton" onClick={goBack}>←</button>
          }
          <img src="https://api.dikript.com/dikript-logo.png" alt="Dikript logo" className="dikriptLogo" />
          <button className="dikriptCloseButton" onClick={closePopup}>×</button>
        </div>
        <h2>Identity Verification</h2>
        {currentStep === 1 ? (
          <div>
            <p className="dikriptSubtitle">{name} will access the following information:</p>
            <div className="dikriptPermissions">
              <div className="dikriptPermissionGroup">
                <h3>{name} will be able to</h3>
                <ul>
                  <li>Access your camera</li>
                  <li>Capture your photo</li>
                  <li>Perform identity verification</li>
                </ul>
              </div>
              <div className="dikriptPermissionGroup">
                <h3>{name} will not be able to</h3>
                <ul>
                  <li>Store your photo permanently</li>
                  <li>Access your other personal data</li>
                  <li>Share your information with third parties</li>
                </ul>
              </div>
            </div>
            <div className="dikriptConsent">
              <label>
                <input
                  type="checkbox"
                  checked={consentGiven}
                  onChange={() => setConsentGiven(!consentGiven)}
                />
                I consent to the processing of my biometric data for identity verification purposes.
              </label>
            </div>
            <button 
              onClick={nextStep} 
              disabled={!consentGiven} 
              className="dikriptActionButton"
            >
              Continue
            </button>
          </div>
        ) : currentStep === 2 ? (
          <div>
            <p className="dikriptSubtitle">Select an ID type and enter your ID number:</p>
            <div className="dikriptIdSelection">
              <select 
                value={selectedIdType} 
                onChange={(e) => setSelectedIdType(e.target.value)}
                className="dikriptIdTypeSelect"
              >
              <option value="">Select ID Type</option>
              {idTypes.map((idType) => (
                <option key={idType.value} value={idType.value}>
                  {idType.label}
                </option>
              ))}
              </select>
              <input 
                type="text" 
                value={idNumber} 
                onChange={(e) => setIdNumber(e.target.value)}
                placeholder="Enter ID Number" 
                className="dikriptIdNumberInput"
              />
            </div>
            <button 
              onClick={nextStep} 
              disabled={!selectedIdType || !idNumber} 
              className="dikriptActionButton"
            >
              Continue
            </button>
          </div>
        ) : currentStep === 3 && !showCamera ? (
          <div className="dikriptCenterContent">
            <p className="dikriptConsentConfirmation">Proceed to liveness check</p>
            <button onClick={startCamera} className="dikriptActionButton">
              Start Camera
            </button>
          </div>
        ) : showCamera ? (
          <div style={{ position: 'relative' }}>
            <div className="dikriptCameraContainer">
              <video ref={videoRef} autoPlay playsInline muted />
              <canvas ref={canvasRef} className="dikriptFaceOverlay"></canvas>
            </div>
            <p className={`dikriptMessage ${isError ? 'dikriptError' : ''} ${isSuccess ? 'dikriptSuccess' : ''}`}>
              {message}
            </p>
            <div className="dikriptButtonContainer">
              {faceDetected && !processing && !identityProcessing && (
                <button onClick={capturePhoto} className="dikriptCaptureButton">
                  Capture Photo
                </button>
              )}
              {showRetry && !identityProcessing && (
                <button onClick={retryCapture} className="dikriptRetryButton">
                  Retry
                </button>
              )}
            </div>
            
            {identityProcessing && (
              <div className="dikriptLoadingOverlay">
                <div className="dikriptLoader"></div>
                <p>Processing identity verification...</p>
                <p>This might take a few moments</p>
              </div>
            )}
          </div>
        ) : currentStep === 4 ? (
          <div className="dikriptCenterContent">
            <p className="dikriptSuccessMessage">Identity comparison completed.</p>
            {identityComparisonResult && (
              <div>
                <p>Match: {identityComparisonResult.isMatch ? 'Yes' : 'No'}</p>
                <p>Confidence: {(identityComparisonResult.confidence * 100).toFixed(2)}%</p>
              </div>
            )}
            <button onClick={closePopup} className="dikriptActionButton">
              Close
            </button>
          </div>
        ) : null}
        <div className="dikriptFooter">
          Powered by Dikript
        </div>
      </div>
    </div>
  );
};

export default IdentityComparisonPopup; 