/**
 * @ai-summary Main camera capture component with viewfinder, crop tool, and file fallback
 * @ai-context Orchestrates camera access, photo capture, cropping, and file selection
 */

import React, { useState, useCallback, useEffect } from 'react';
import { Box, Alert, Button, Typography, CircularProgress } from '@mui/material';
import CameraAltIcon from '@mui/icons-material/CameraAlt';
import UploadFileIcon from '@mui/icons-material/UploadFile';
import type { CameraCaptureProps, CaptureState } from './types';
import {
  DEFAULT_ACCEPTED_FORMATS,
  DEFAULT_MAX_FILE_SIZE,
  GUIDANCE_CONFIGS,
  getInitialCropForGuidance,
} from './types';
import { useCameraPermission } from './useCameraPermission';
import { CameraViewfinder } from './CameraViewfinder';
import { CropTool } from './CropTool';
import { FileInputFallback } from './FileInputFallback';

export const CameraCapture: React.FC<CameraCaptureProps> = ({
  onCapture,
  onCancel,
  guidanceType = 'none',
  allowCrop = true,
  maxFileSize = DEFAULT_MAX_FILE_SIZE,
  acceptedFormats = DEFAULT_ACCEPTED_FORMATS,
}) => {
  const [captureState, setCaptureState] = useState<CaptureState>('idle');
  const [capturedImageSrc, setCapturedImageSrc] = useState<string | null>(null);
  const [capturedFile, setCapturedFile] = useState<File | null>(null);
  const [useFallback, setUseFallback] = useState(false);

  const {
    permissionState,
    stream,
    error: cameraError,
    facingMode,
    hasMultipleCameras,
    requestPermission,
    switchCamera,
    stopStream,
  } = useCameraPermission();

  // Request camera permission on mount
  useEffect(() => {
    if (captureState === 'idle' && !useFallback) {
      setCaptureState('viewfinder');
      requestPermission();
    }
  }, [captureState, useFallback, requestPermission]);

  // Clean up on unmount
  useEffect(() => {
    return () => {
      stopStream();
      if (capturedImageSrc) {
        URL.revokeObjectURL(capturedImageSrc);
      }
    };
  }, [stopStream, capturedImageSrc]);

  const handleCapture = useCallback(() => {
    if (!stream) return;

    // Get video element from stream
    const videoTracks = stream.getVideoTracks();
    if (videoTracks.length === 0) return;

    const videoTrack = videoTracks[0];
    const settings = videoTrack.getSettings();

    // Create canvas for capture
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    // Find the video element to capture from
    const videoElements = document.querySelectorAll('video');
    let sourceVideo: HTMLVideoElement | null = null;

    for (const video of videoElements) {
      if (video.srcObject === stream) {
        sourceVideo = video;
        break;
      }
    }

    if (!sourceVideo) return;

    // Set canvas size to video dimensions
    canvas.width = settings.width || sourceVideo.videoWidth || 1920;
    canvas.height = settings.height || sourceVideo.videoHeight || 1080;

    // Draw video frame to canvas
    ctx.drawImage(sourceVideo, 0, 0, canvas.width, canvas.height);

    // Convert to blob
    canvas.toBlob(
      (blob) => {
        if (!blob) return;

        // Create file from blob
        const file = new File([blob], `capture-${Date.now()}.jpg`, {
          type: 'image/jpeg',
        });

        setCapturedFile(file);
        setCapturedImageSrc(URL.createObjectURL(blob));

        if (allowCrop) {
          setCaptureState('cropping');
        } else {
          // Skip cropping, directly complete
          onCapture(file);
          stopStream();
        }
      },
      'image/jpeg',
      0.92
    );
  }, [stream, allowCrop, onCapture, stopStream]);

  const handleCropConfirm = useCallback(
    (croppedBlob: Blob) => {
      if (!capturedFile) return;

      const croppedFile = new File(
        [croppedBlob],
        `cropped-${capturedFile.name}`,
        { type: croppedBlob.type }
      );

      onCapture(capturedFile, croppedFile);
      stopStream();
    },
    [capturedFile, onCapture, stopStream]
  );

  const handleCropSkip = useCallback(() => {
    if (!capturedFile) return;
    onCapture(capturedFile);
    stopStream();
  }, [capturedFile, onCapture, stopStream]);

  const handleRetake = useCallback(() => {
    if (capturedImageSrc) {
      URL.revokeObjectURL(capturedImageSrc);
    }
    setCapturedFile(null);
    setCapturedImageSrc(null);
    setCaptureState('viewfinder');

    // Re-request camera if stream tracks are no longer active
    const isStreamActive = stream?.getVideoTracks().some(
      (track) => track.readyState === 'live'
    );
    if (!isStreamActive) {
      requestPermission();
    }
  }, [capturedImageSrc, stream, requestPermission]);

  const handleCropReset = useCallback(() => {
    // Just reset crop area, keep the captured image
  }, []);

  const handleCancel = useCallback(() => {
    stopStream();
    if (capturedImageSrc) {
      URL.revokeObjectURL(capturedImageSrc);
    }
    onCancel();
  }, [stopStream, capturedImageSrc, onCancel]);

  const handleFileSelect = useCallback(
    (file: File) => {
      setCapturedFile(file);
      setCapturedImageSrc(URL.createObjectURL(file));

      if (allowCrop) {
        setCaptureState('cropping');
      } else {
        onCapture(file);
      }
    },
    [allowCrop, onCapture]
  );

  const handleSwitchToFallback = useCallback(() => {
    stopStream();
    setUseFallback(true);
  }, [stopStream]);

  const handleSwitchToCamera = useCallback(() => {
    setUseFallback(false);
    setCaptureState('idle');
  }, []);

  // Get aspect ratio for crop tool if guidance type is set
  const cropAspectRatio =
    guidanceType !== 'none' ? GUIDANCE_CONFIGS[guidanceType].aspectRatio : undefined;

  // Calculate crop coordinates centered on the guidance overlay area
  const cropInitialArea = getInitialCropForGuidance(guidanceType);

  // Render permission error state
  if (permissionState === 'denied' && !useFallback) {
    return (
      <PermissionErrorView
        error={cameraError || 'Camera permission denied'}
        onUseFileInput={handleSwitchToFallback}
        onCancel={handleCancel}
      />
    );
  }

  // Render unavailable state
  if (permissionState === 'unavailable' && !useFallback) {
    return (
      <PermissionErrorView
        error={cameraError || 'Camera not available'}
        onUseFileInput={handleSwitchToFallback}
        onCancel={handleCancel}
      />
    );
  }

  // Render file input fallback
  if (useFallback) {
    return (
      <Box sx={{ width: '100%', height: '100%' }}>
        <FileInputFallback
          onFileSelect={handleFileSelect}
          onCancel={handleCancel}
          acceptedFormats={acceptedFormats}
          maxFileSize={maxFileSize}
        />
        {/* Option to switch back to camera if available */}
        {permissionState !== 'unavailable' && permissionState !== 'denied' && (
          <Box sx={{ p: 2, textAlign: 'center' }}>
            <Button
              onClick={handleSwitchToCamera}
              startIcon={<CameraAltIcon />}
              variant="text"
            >
              Use Camera Instead
            </Button>
          </Box>
        )}
      </Box>
    );
  }

  // Render crop tool
  if (captureState === 'cropping' && capturedImageSrc) {
    return (
      <CropTool
        imageSrc={capturedImageSrc}
        initialCrop={cropInitialArea}
        lockAspectRatio={guidanceType !== 'none' && guidanceType !== 'vin'}
        aspectRatio={cropAspectRatio}
        onConfirm={handleCropConfirm}
        onReset={handleCropReset}
        onRetake={handleRetake}
        onSkip={handleCropSkip}
      />
    );
  }

  // Render loading state
  if (!stream && permissionState === 'prompt') {
    return (
      <Box
        sx={{
          width: '100%',
          height: '100%',
          display: 'flex',
          flexDirection: 'column',
          alignItems: 'center',
          justifyContent: 'center',
          backgroundColor: 'black',
          color: 'white',
          gap: 2,
        }}
      >
        <CircularProgress color="inherit" />
        <Typography>Requesting camera access...</Typography>
        <Button
          onClick={handleSwitchToFallback}
          startIcon={<UploadFileIcon />}
          sx={{ color: 'white', mt: 2 }}
        >
          Upload File Instead
        </Button>
      </Box>
    );
  }

  // Render viewfinder
  return (
    <Box sx={{ width: '100%', height: '100%', position: 'relative' }}>
      <CameraViewfinder
        stream={stream}
        guidanceType={guidanceType}
        onCapture={handleCapture}
        onCancel={handleCancel}
        onSwitchCamera={switchCamera}
        canSwitchCamera={hasMultipleCameras}
        facingMode={facingMode}
      />

      {/* Fallback option button */}
      <Box
        sx={{
          position: 'absolute',
          bottom: 100,
          left: '50%',
          transform: 'translateX(-50%)',
          zIndex: 10,
        }}
      >
        <Button
          onClick={handleSwitchToFallback}
          startIcon={<UploadFileIcon />}
          size="small"
          sx={{
            color: 'white',
            backgroundColor: 'rgba(0, 0, 0, 0.3)',
            '&:hover': {
              backgroundColor: 'rgba(0, 0, 0, 0.5)',
            },
          }}
        >
          Upload File
        </Button>
      </Box>
    </Box>
  );
};

interface PermissionErrorViewProps {
  error: string;
  onUseFileInput: () => void;
  onCancel: () => void;
}

const PermissionErrorView: React.FC<PermissionErrorViewProps> = ({
  error,
  onUseFileInput,
  onCancel,
}) => (
  <Box
    sx={{
      width: '100%',
      height: '100%',
      display: 'flex',
      flexDirection: 'column',
      alignItems: 'center',
      justifyContent: 'center',
      p: 3,
      gap: 3,
      backgroundColor: 'background.paper',
    }}
  >
    <Alert severity="warning" sx={{ maxWidth: 400 }}>
      {error}
    </Alert>

    <Typography variant="body2" color="text.secondary" textAlign="center">
      You can still upload images from your device
    </Typography>

    <Box sx={{ display: 'flex', gap: 2, flexWrap: 'wrap', justifyContent: 'center' }}>
      <Button
        variant="contained"
        onClick={onUseFileInput}
        startIcon={<UploadFileIcon />}
      >
        Upload File
      </Button>

      <Button variant="outlined" onClick={onCancel}>
        Cancel
      </Button>
    </Box>
  </Box>
);

export default CameraCapture;
