import React, { useEffect, useMemo, useState, useRef } from "react";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table";
import { Button } from "@/components/ui/button";
import { Delete, Edit, Eye, FileCheck, Upload, X, FileText, Camera, RefreshCw } from "lucide-react";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, } from "@/components/ui/pagination";
import { apiRequest, queryClient, API_BASE_URL } from "@/lib/queryClient";
import { useMutation, useQuery } from "@tanstack/react-query";
import LoadingScreen from "@/components/ui/LoadingScreen";
import { useToast } from "@/hooks/use-toast";
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "@/components/ui/dialog";
import { AddPatientModal } from "./add-patient-modal";
import { DeleteConfirmationDialog } from "@/components/ui/deleteDialog";
import { useAuth } from "@/hooks/use-auth";
import { PatientSearch } from "./patient-search";
import { useDebounce } from "use-debounce";
import { cn } from "@/lib/utils";
import { Checkbox } from "@/components/ui/checkbox";
import { formatDateToHumanReadable } from "@/utils/dateUtils";
import { PatientFinancialsModal } from "./patient-financial-modal";
import { getPageNumbers } from "@/utils/pageNumberGenerator";
import { uploadDocument, getPatientDocuments, deleteDocument } from "@/lib/api/documents";
// 🔑 exported base key
export const QK_PATIENTS_BASE = ["patients"];
// helper (optional) – mirrors your current key structure
export const qkPatients = (page, search) => [...QK_PATIENTS_BASE, { page, search }];
export function PatientTable({ allowEdit, allowView, allowDelete, allowCheckbox, allowNewClaim, allowFinancial, onNewClaim, onSelectPatient, onPageChange, onSearchChange, }) {
    const { toast } = useToast();
    const { user } = useAuth();
    const isAdmin = user?.username === "admin";
    const [currentPatient, setCurrentPatient] = useState(undefined);
    const [isAddPatientOpen, setIsAddPatientOpen] = useState(false);
    const [isViewPatientOpen, setIsViewPatientOpen] = useState(false);
    const [isDeletePatientOpen, setIsDeletePatientOpen] = useState(false);
    const [isFinancialsOpen, setIsFinancialsOpen] = useState(false);
    const [modalPatientId, setModalPatientId] = useState(null);
    const [currentPage, setCurrentPage] = useState(1);
    const patientsPerPage = 5;
    const offset = (currentPage - 1) * patientsPerPage;
    const [isSearchActive, setIsSearchActive] = useState(false);
    const [searchCriteria, setSearchCriteria] = useState(null);
    const [debouncedSearchCriteria] = useDebounce(searchCriteria, 500);
    const [selectedPatientId, setSelectedPatientId] = useState(null);
    const [expandedPatientId, setExpandedPatientId] = useState(null);
    // Real document data state
    const [patientDocuments, setPatientDocuments] = useState({});
    const [documentsLoading, setDocumentsLoading] = useState({});
    // Document viewer modal state
    const [documentViewerOpen, setDocumentViewerOpen] = useState(false);
    const [viewingDocument, setViewingDocument] = useState(null);
    // Thumbnail cache for image documents
    const [documentThumbnails, setDocumentThumbnails] = useState({});
    // Camera modal state
    const [cameraOpen, setCameraOpen] = useState(false);
    const [selectedPatientIdForCamera, setSelectedPatientIdForCamera] = useState(null);
    const [stream, setStream] = useState(null);
    const [capturedImage, setCapturedImage] = useState(null);
    const [cameraPermission, setCameraPermission] = useState('unknown');
    const [isRequestingPermission, setIsRequestingPermission] = useState(false);
    const videoRef = useRef(null);
    const canvasRef = useRef(null);
    const [facingMode, setFacingMode] = useState('environment');
    // Cleanup blob URL when modal closes
    const handleDocumentViewerClose = () => {
        if (viewingDocument && viewingDocument.url.startsWith('blob:')) {
            URL.revokeObjectURL(viewingDocument.url);
        }
        setDocumentViewerOpen(false);
        setViewingDocument(null);
    };
    // Get thumbnail URL for image documents
    const getDocumentThumbnail = async (doc) => {
        if (!doc.mimeType.startsWith('image/')) {
            return null;
        }
        try {
            // Use the full URL from the database directly
            const documentUrl = doc.filePath;
            // Static files don't need authentication headers
            const response = await fetch(documentUrl);
            if (!response.ok) {
                return null;
            }
            const blob = await response.blob();
            return URL.createObjectURL(blob);
        }
        catch (error) {
            console.error('Error loading thumbnail:', error);
            return null;
        }
    };
    // Load thumbnails for image documents
    const loadDocumentThumbnails = async (documents) => {
        const imageDocs = documents.filter(doc => doc.mimeType.startsWith('image/'));
        for (const doc of imageDocs) {
            if (!documentThumbnails[doc.id]) {
                const thumbnailUrl = await getDocumentThumbnail(doc);
                setDocumentThumbnails(prev => ({
                    ...prev,
                    [doc.id]: thumbnailUrl
                }));
            }
        }
    };
    // Check camera permissions
    const checkCameraPermission = async () => {
        try {
            console.log('Checking camera permission...');
            const permission = await navigator.permissions.query({ name: 'camera' });
            console.log('Permission state:', permission.state);
            setCameraPermission(permission.state);
            // Listen for permission changes
            permission.addEventListener('change', () => {
                console.log('Permission changed to:', permission.state);
                setCameraPermission(permission.state);
            });
            return permission.state;
        }
        catch (error) {
            console.log('Permission API not supported, will try getUserMedia directly');
            return 'unknown';
        }
    };
    // Check if running on localhost vs remote IP
    const isLocalhost = () => {
        return window.location.hostname === 'localhost' ||
            window.location.hostname === '127.0.0.1' ||
            window.location.hostname.includes('localhost');
    };
    // Check if any camera devices are available
    const checkCameraDevices = async () => {
        try {
            const devices = await navigator.mediaDevices.enumerateDevices();
            const videoDevices = devices.filter(device => device.kind === 'videoinput');
            console.log('Available camera devices:', videoDevices.length);
            console.log('Current hostname:', window.location.hostname);
            console.log('Is localhost:', isLocalhost());
            return videoDevices.length > 0;
        }
        catch (error) {
            console.error('Error checking camera devices:', error);
            return false;
        }
    };
    // Request camera permission
    const requestCameraPermission = async () => {
        setIsRequestingPermission(true);
        // Check if running on secure context
        if (!isLocalhost() && window.location.protocol !== 'https:') {
            toast({
                title: "HTTPS Required",
                description: "Camera access requires HTTPS when accessing from remote devices. Please use https:// or access from localhost.",
                variant: "destructive",
            });
            setIsRequestingPermission(false);
            return false;
        }
        // First check if any camera devices are available
        const hasCamera = await checkCameraDevices();
        if (!hasCamera) {
            toast({
                title: "No Camera Found",
                description: "No camera device was detected. Please ensure you have a camera connected and try again.",
                variant: "destructive",
            });
            setIsRequestingPermission(false);
            return false;
        }
        try {
            console.log('Requesting camera permission...');
            const mediaStream = await navigator.mediaDevices.getUserMedia({
                video: {
                    facingMode: 'environment',
                    width: { ideal: 1920 },
                    height: { ideal: 1080 }
                }
            });
            console.log('Camera permission granted!');
            // Permission granted
            setCameraPermission('granted');
            setStream(mediaStream);
            if (videoRef.current) {
                videoRef.current.srcObject = mediaStream;
            }
            // Stop the stream for now, will be started when needed
            mediaStream.getTracks().forEach(track => track.stop());
            setStream(null);
            toast({
                title: "Camera Permission Granted",
                description: "You can now use the camera to scan documents",
            });
            return true;
        }
        catch (error) {
            console.error('Camera permission error:', error);
            // Handle different types of camera errors
            if (error.name === 'NotFoundError' || error.message.includes('Requested device not found')) {
                setCameraPermission('denied');
                toast({
                    title: "No Camera Found",
                    description: "No camera device was detected. Please ensure you have a camera connected and try again.",
                    variant: "destructive",
                });
            }
            else if (error.name === 'NotAllowedError' || error.message.includes('Permission denied')) {
                setCameraPermission('denied');
                toast({
                    title: "Camera Permission Denied",
                    description: "Please allow camera access in your browser settings to scan documents",
                    variant: "destructive",
                });
            }
            else if (error.name === 'NotReadableError' || error.message.includes('Already in use')) {
                setCameraPermission('denied');
                toast({
                    title: "Camera Already in Use",
                    description: "The camera is being used by another application. Please close other apps using the camera and try again.",
                    variant: "destructive",
                });
            }
            else if (error.name === 'NotSupportedError' || error.message.includes('secure context')) {
                setCameraPermission('denied');
                toast({
                    title: "HTTPS Required",
                    description: "Camera access requires HTTPS. Please use https:// or access from localhost for development.",
                    variant: "destructive",
                });
            }
            else {
                setCameraPermission('denied');
                toast({
                    title: "Camera Error",
                    description: "Unable to access camera. Please check your camera settings and try again.",
                    variant: "destructive",
                });
            }
            return false;
        }
        finally {
            setIsRequestingPermission(false);
        }
    };
    // Camera functions
    const startCamera = async () => {
        try {
            const mediaStream = await navigator.mediaDevices.getUserMedia({
                video: {
                    facingMode: facingMode,
                    width: { ideal: 1920 },
                    height: { ideal: 1080 }
                }
            });
            setStream(mediaStream);
            if (videoRef.current) {
                videoRef.current.srcObject = mediaStream;
            }
        }
        catch (error) {
            console.error('Error accessing camera:', error);
            toast({
                title: "Camera Error",
                description: "Unable to access camera. Please check permissions.",
                variant: "destructive",
            });
        }
    };
    const stopCamera = () => {
        if (stream) {
            stream.getTracks().forEach(track => track.stop());
            setStream(null);
        }
    };
    const capturePhoto = () => {
        if (videoRef.current && canvasRef.current) {
            const video = videoRef.current;
            const canvas = canvasRef.current;
            const context = canvas.getContext('2d');
            if (context) {
                canvas.width = video.videoWidth;
                canvas.height = video.videoHeight;
                context.drawImage(video, 0, 0, canvas.width, canvas.height);
                const imageData = canvas.toDataURL('image/jpeg', 0.8);
                setCapturedImage(imageData);
                stopCamera();
            }
        }
    };
    const retakePhoto = () => {
        setCapturedImage(null);
        startCamera();
    };
    const toggleFacingMode = () => {
        setFacingMode(prev => prev === 'user' ? 'environment' : 'user');
        if (stream) {
            stopCamera();
        }
    };
    // Restart camera when facingMode changes
    useEffect(() => {
        if (cameraOpen && !capturedImage) {
            startCamera();
        }
    }, [facingMode]);
    const handleFinancialsModalChange = (v) => {
        setIsFinancialsOpen(v);
        if (!v)
            setModalPatientId(null);
    };
    const handleScanDocument = async (patientId) => {
        console.log('handleScanDocument called with patientId:', patientId);
        if (!patientId) {
            console.error('No patient ID provided');
            toast({
                title: "Error",
                description: "Please select a patient first",
                variant: "destructive",
            });
            return;
        }
        setSelectedPatientIdForCamera(patientId);
        setCapturedImage(null);
        setFacingMode('environment'); // Reset to back camera by default
        // Directly request permission which triggers browser prompt
        const granted = await requestCameraPermission();
        if (granted) {
            setCameraOpen(true);
        }
    };
    const handleCameraClose = () => {
        stopCamera();
        setCameraOpen(false);
        setSelectedPatientIdForCamera(null);
        setCapturedImage(null);
    };
    const saveCapturedPhoto = async () => {
        if (!capturedImage || !selectedPatientIdForCamera)
            return;
        try {
            // Convert data URL to blob
            const response = await fetch(capturedImage);
            const blob = await response.blob();
            const file = new File([blob], `scan_${Date.now()}.jpg`, { type: 'image/jpeg' });
            // Upload using existing upload function
            await uploadDocument(selectedPatientIdForCamera, file);
            // Emit document upload event
            window.dispatchEvent(new CustomEvent('documentUploaded', {
                detail: { patientId: selectedPatientIdForCamera, fileName: `scan_${Date.now()}.jpg` }
            }));
            // Also set storage event for cross-tab communication
            localStorage.setItem('documentUploaded', Date.now().toString());
            // Refresh documents for this patient
            await loadPatientDocuments(selectedPatientIdForCamera);
            toast({
                title: "Success",
                description: "Document scanned and uploaded successfully",
                variant: "default",
            });
            handleCameraClose();
        }
        catch (error) {
            console.error('Error saving scanned document:', error);
            toast({
                title: "Error",
                description: "Failed to save scanned document",
                variant: "destructive",
            });
        }
    };
    // Start camera when modal opens
    useEffect(() => {
        if (cameraOpen && !capturedImage) {
            startCamera();
        }
        return () => {
            if (stream) {
                stopCamera();
            }
        };
    }, [cameraOpen, capturedImage]);
    const handleSelectPatient = (patient) => {
        const isSelected = selectedPatientId === patient.id;
        const newSelectedId = isSelected ? null : patient.id;
        setSelectedPatientId(newSelectedId ? Number(newSelectedId) : null);
        if (onSelectPatient) {
            onSelectPatient(isSelected ? null : patient);
        }
    };
    const handleClearSelection = () => {
        setSelectedPatientId(null);
        if (onSelectPatient) {
            onSelectPatient(null);
        }
    };
    const handleUploadFiles = async () => {
        if (selectedPatientId) {
            const input = document.createElement('input');
            input.type = 'file';
            input.multiple = true;
            input.accept = '.pdf,.jpg,.jpeg,.png,.doc,.docx';
            input.onchange = async (e) => {
                const files = e.target.files;
                if (files && files.length > 0) {
                    try {
                        const uploadPromises = Array.from(files).map(file => uploadDocument(selectedPatientId, file));
                        const results = await Promise.all(uploadPromises);
                        // Emit document upload event
                        window.dispatchEvent(new CustomEvent('documentUploaded', {
                            detail: { patientId: selectedPatientId, fileCount: files.length, files: Array.from(files).map(f => f.name) }
                        }));
                        // Also set storage event for cross-tab communication
                        localStorage.setItem('documentUploaded', Date.now().toString());
                        // Refresh documents for this patient
                        await loadPatientDocuments(selectedPatientId);
                        toast({
                            title: "Files Uploaded",
                            description: `${files.length} file(s) uploaded successfully to patient ID: ${selectedPatientId}`,
                            variant: "default",
                        });
                    }
                    catch (error) {
                        console.error('Upload error:', error);
                        toast({
                            title: "Upload Failed",
                            description: error instanceof Error ? error.message : "Failed to upload files",
                            variant: "destructive",
                        });
                    }
                }
            };
            input.click();
        }
    };
    // Load documents for a patient
    const loadPatientDocuments = async (patientId) => {
        try {
            setDocumentsLoading(prev => ({ ...prev, [patientId]: true }));
            const response = await getPatientDocuments(patientId);
            setPatientDocuments(prev => ({ ...prev, [patientId]: response.documents }));
            // Load thumbnails for image documents
            await loadDocumentThumbnails(response.documents);
        }
        catch (error) {
            console.error('Error loading documents:', error);
            toast({
                title: "Error",
                description: "Failed to load documents",
                variant: "destructive",
            });
        }
        finally {
            setDocumentsLoading(prev => ({ ...prev, [patientId]: false }));
        }
    };
    const handleToggleDocuments = async (patientId) => {
        const isExpanding = expandedPatientId !== patientId;
        setExpandedPatientId(isExpanding ? patientId : null);
        // Load documents if expanding and not already loaded
        if (isExpanding && !patientDocuments[patientId]) {
            await loadPatientDocuments(patientId);
        }
    };
    const handleViewDocument = async (documentId, patientId) => {
        try {
            const doc = patientDocuments[patientId]?.find(doc => doc.id === documentId);
            if (!doc) {
                console.error('Document not found');
                return;
            }
            // Use the full URL from the database directly
            const documentUrl = doc.filePath;
            // For images, fetch and convert to blob URL for modal viewing
            if (doc.mimeType.startsWith('image/')) {
                // Static files don't need authentication headers
                const response = await fetch(documentUrl);
                if (!response.ok) {
                    throw new Error('Failed to fetch document');
                }
                const blob = await response.blob();
                const url = URL.createObjectURL(blob);
                setViewingDocument({ url, name: doc.originalName });
                setDocumentViewerOpen(true);
            }
            else {
                // For PDFs and other files, open in new tab
                const link = document.createElement('a');
                link.href = documentUrl;
                link.target = '_blank';
                link.rel = 'noopener noreferrer';
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
            }
        }
        catch (error) {
            console.error('Error viewing document:', error);
            toast({
                title: "Error",
                description: "Failed to view document. Please try again.",
                variant: "destructive",
            });
        }
    };
    const handleDownloadDocument = async (documentId, patientId) => {
        try {
            const doc = patientDocuments[patientId]?.find(doc => doc.id === documentId);
            if (!doc) {
                toast({
                    title: "Error",
                    description: "Document not found",
                    variant: "destructive",
                });
                return;
            }
            // Use the full URL from the database directly
            const documentUrl = doc.filePath;
            // For better download experience, fetch the file and create blob URL
            try {
                const response = await fetch(documentUrl);
                if (!response.ok) {
                    throw new Error('Failed to fetch document for download');
                }
                const blob = await response.blob();
                const blobUrl = URL.createObjectURL(blob);
                // Create a temporary link and trigger download
                const link = document.createElement('a');
                link.href = blobUrl;
                link.download = doc.originalName;
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
                // Clean up blob URL
                URL.revokeObjectURL(blobUrl);
            }
            catch (fetchError) {
                // Fallback to direct link if fetch fails
                const link = document.createElement('a');
                link.href = documentUrl;
                link.download = doc.originalName;
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
            }
            toast({
                title: "Success",
                description: "Document downloaded successfully",
            });
        }
        catch (error) {
            console.error('Error downloading document:', error);
            toast({
                title: "Error",
                description: "Failed to download document. Please try again.",
                variant: "destructive",
            });
        }
    };
    const handleDeleteDocument = async (documentId, patientId) => {
        try {
            await deleteDocument(documentId);
            // Refresh documents for this patient
            await loadPatientDocuments(patientId);
            toast({
                title: "Document Deleted",
                description: "Document has been deleted successfully",
                variant: "default",
            });
        }
        catch (error) {
            console.error('Error deleting document:', error);
            toast({
                title: "Error",
                description: error instanceof Error ? error.message : "Failed to delete document",
                variant: "destructive",
            });
        }
    };
    const searchKeyPart = debouncedSearchCriteria?.searchTerm || "recent";
    const { data: patientsData, isLoading, isError, } = useQuery({
        queryKey: qkPatients(currentPage, searchKeyPart),
        queryFn: async () => {
            const trimmedTerm = debouncedSearchCriteria?.searchTerm?.trim();
            const isSearch = trimmedTerm && trimmedTerm.length > 0;
            const rawSearchBy = debouncedSearchCriteria?.searchBy || "name";
            const validSearchKeys = [
                "name",
                "phone",
                "insuranceId",
                "gender",
                "dob",
                "all",
            ];
            const searchKey = validSearchKeys.includes(rawSearchBy)
                ? rawSearchBy
                : "name";
            let url;
            if (isSearch) {
                const searchParams = new URLSearchParams({
                    limit: String(patientsPerPage),
                    offset: String(offset),
                });
                if (searchKey === "all") {
                    searchParams.set("term", trimmedTerm);
                }
                else {
                    searchParams.set(searchKey, trimmedTerm);
                }
                url = `/api/patients/search?${searchParams.toString()}`;
            }
            else {
                url = `/api/patients/recent?limit=${patientsPerPage}&offset=${offset}`;
            }
            const token = localStorage.getItem("token");
            const res = await fetch(`${API_BASE_URL}${url}`, {
                headers: {
                    ...(token ? { Authorization: `Bearer ${token}` } : {}),
                },
                credentials: "include",
            });
            if (res.status === 401 || res.status === 403) {
                return { patients: [], totalCount: 0 };
            }
            if (!res.ok) {
                const errorData = await res.json().catch(() => ({}));
                throw new Error(errorData.message || "Failed to load patients");
            }
            return res.json();
        },
        placeholderData: {
            patients: [],
            totalCount: 0,
        },
    });
    // Update patient mutation
    const updatePatientMutation = useMutation({
        mutationFn: async ({ id, patient, }) => {
            const res = await apiRequest("PUT", `/api/patients/${id}`, patient);
            return res.json();
        },
        onSuccess: async () => {
            setIsAddPatientOpen(false);
            // this query every page,
            await queryClient.invalidateQueries({ queryKey: QK_PATIENTS_BASE });
            toast({
                title: "Success",
                description: "Patient updated successfully!",
                variant: "default",
            });
        },
        onError: (error) => {
            toast({
                title: "Error",
                description: `Failed to update patient: ${error.message}`,
                variant: "destructive",
            });
        },
    });
    const deletePatientMutation = useMutation({
        mutationFn: async (id) => {
            const res = await apiRequest("DELETE", `/api/patients/${id}`);
            return;
        },
        onSuccess: async () => {
            setIsDeletePatientOpen(false);
            await queryClient.invalidateQueries({ queryKey: QK_PATIENTS_BASE });
            toast({
                title: "Success",
                description: "Patient deleted successfully!",
                variant: "default",
            });
        },
        onError: (error) => {
            console.log(error);
            toast({
                title: "Error",
                description: `Failed to delete patient: ${error.message}`,
                variant: "destructive",
            });
        },
    });
    const handleUpdatePatient = (patient) => {
        if (currentPatient && user) {
            const { id, ...sanitizedPatient } = patient;
            updatePatientMutation.mutate({
                id: Number(currentPatient.id),
                patient: sanitizedPatient,
            });
        }
        else {
            console.error("No current patient or user found for update");
            toast({
                title: "Error",
                description: "Cannot update patient: No patient or user found",
                variant: "destructive",
            });
        }
    };
    const handleEditPatient = (patient) => {
        setCurrentPatient(patient);
        setIsAddPatientOpen(true);
    };
    const handleViewPatient = (patient) => {
        setCurrentPatient(patient);
        setIsViewPatientOpen(true);
    };
    const handleDeletePatient = (patient) => {
        setCurrentPatient(patient);
        setIsDeletePatientOpen(true);
    };
    const handleConfirmDeletePatient = async () => {
        if (currentPatient) {
            deletePatientMutation.mutate(Number(currentPatient.id));
        }
        else {
            toast({
                title: "Error",
                description: "No patient selected for deletion.",
                variant: "destructive",
            });
        }
    };
    useEffect(() => {
        if (onPageChange)
            onPageChange(currentPage);
    }, [currentPage, onPageChange]);
    useEffect(() => {
        const term = debouncedSearchCriteria?.searchTerm?.trim() || "recent";
        if (onSearchChange)
            onSearchChange(term);
    }, [debouncedSearchCriteria, onSearchChange]);
    const totalPages = useMemo(() => Math.ceil((patientsData?.totalCount || 0) / patientsPerPage), [patientsData]);
    const startItem = offset + 1;
    const endItem = Math.min(offset + patientsPerPage, patientsData?.totalCount || 0);
    const getInitials = (firstName, lastName) => {
        return (firstName.charAt(0) + lastName.charAt(0)).toUpperCase();
    };
    const getAvatarColor = (id) => {
        const colorClasses = [
            "bg-blue-500",
            "bg-teal-500",
            "bg-amber-500",
            "bg-rose-500",
            "bg-indigo-500",
            "bg-green-500",
            "bg-purple-500",
        ];
        return colorClasses[id % colorClasses.length];
    };
    return (<div className="bg-white shadow rounded-lg overflow-hidden">
      {/* Selection Panel */}
      {!!selectedPatientId && (<div className="bg-red-50 border border-red-200 rounded-tl-md rounded-tr-md px-4 py-3 flex items-center justify-between">
          <div className="flex items-center space-x-2">
            <span className="text-sm font-medium text-red-800">
              1 patient selected
            </span>
          </div>
          <div className="flex items-center space-x-2">
            <Button variant="outline" size="sm" onClick={() => handleScanDocument(selectedPatientId)} className="flex items-center space-x-1 text-white bg-green-600 hover:bg-green-500 hover:text-white transition-all duration-300 ease-in-out">
              <Camera className="h-4 w-4"/>
              <span>Scan Document</span>
            </Button>
            <Button variant="outline" size="sm" onClick={handleUploadFiles} className="flex items-center space-x-1 bg-blue-500 text-white hover:bg-blue-400 hover:text-white transition-all duration-300 ease-in-out">
              <Upload className="h-4 w-4"/>
              <span>Upload Files</span>
            </Button>
            <Button variant="outline" size="sm" onClick={handleClearSelection} className="flex items-center space-x-1 border-red-300 text-red-700 hover:bg-red-100 transition-all duration-300 ease-in-out">
              <X className="h-4 w-4"/>
              <span>Clear selection</span>
            </Button>
          </div>
        </div>)}

      <div className="overflow-x-auto">
        <PatientSearch onSearch={(criteria) => {
            setSearchCriteria(criteria);
            setCurrentPage(1); // reset page on new search
            setIsSearchActive(true);
        }} onClearSearch={() => {
            setSearchCriteria({ searchTerm: "", searchBy: "name" }); // triggers `recent`
            setCurrentPage(1);
            setIsSearchActive(false);
        }} isSearchActive={isSearchActive}/>
        <Table>
          <TableHeader>
            <TableRow>
              {allowCheckbox && <TableHead>Select</TableHead>}
              <TableHead>Patient</TableHead>
              <TableHead>DOB</TableHead>
              {/*<TableHead>Contact</TableHead>*/}
              <TableHead>Insurance</TableHead>
              <TableHead>Status</TableHead>
              <TableHead className="text-right">Actions</TableHead>
            </TableRow>
          </TableHeader>
          <TableBody>
            {isLoading ? (<TableRow>
                <TableCell colSpan={6} className="text-center py-8 text-muted-foreground">
                  <LoadingScreen />
                </TableCell>
              </TableRow>) : isError ? (<TableRow>
                <TableCell colSpan={6} className="text-center py-8 text-red-500">
                  Error loading patients.
                </TableCell>
              </TableRow>) : patientsData?.patients.length === 0 ? (<TableRow>
                <TableCell colSpan={6} className="text-center py-8 text-muted-foreground">
                  No patients found.
                </TableCell>
              </TableRow>) : (patientsData?.patients.map((patient) => (<React.Fragment key={patient.id}>
                  <TableRow className="hover:bg-gray-50">
                    {allowCheckbox && (<TableCell>
                        <Checkbox checked={selectedPatientId === patient.id} onCheckedChange={() => handleSelectPatient(patient)}/>
                      </TableCell>)}

                    <TableCell>
                      <div className="flex items-center">
                        <Avatar className={`h-10 w-10 ${getAvatarColor(Number(patient.id))}`}>
                          <AvatarFallback className="text-white">
                            {getInitials(patient.firstName, patient.lastName)}
                          </AvatarFallback>
                        </Avatar>

                        <div className="ml-4">
                          <div className="text-sm font-medium text-gray-900">
                            {patient.firstName} {patient.lastName}
                          </div>
                          <div className="text-sm text-gray-500">
                            PID-{patient.id?.toString().padStart(4, "0")}
                          </div>
                        </div>
                      </div>
                    </TableCell>
                    <TableCell>
                      <div className="text-sm text-gray-900">
                        {formatDateToHumanReadable(patient.dateOfBirth)}
                      </div>
                      <div className="text-sm text-gray-500 capitalize">
                        {patient.gender}
                      </div>
                    </TableCell>
                    {/*<TableCell>
              <div className="text-sm text-gray-900">{patient.phone}</div>
              <div className="text-sm text-gray-500">{patient.email}</div>
            </TableCell>*/}
                    <TableCell>
                      <div className="text-sm text-gray-900">
                        {patient.insuranceProvider ?? "Not specified"}
                      </div>
                      {patient.insuranceId && (<div className="text-sm text-gray-500">
                          ID: {patient.insuranceId}
                        </div>)}
                    </TableCell>
                    <TableCell>
                      <div className="col-span-1">
                        {patient.status === "ACTIVE" && (<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
                            Active
                          </span>)}

                        {patient.status === "INACTIVE" && (<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">
                            Inactive
                          </span>)}

                        {patient.status === "UNKNOWN" && (<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-200 text-gray-700">
                            Unknown
                          </span>)}

                        {patient.status === "PLAN_NOT_ACCEPTED" && (<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-amber-100 text-amber-800">
                            Plan Not Accepted
                          </span>)}
                      </div>
                    </TableCell>

                    <TableCell className="text-right">
                      <div className="flex justify-end">
                        {allowDelete && isAdmin && (<Button onClick={() => {
                    handleDeletePatient(patient);
                }} className="text-red-600 hover:text-red-900" aria-label="Delete Patient" variant="ghost" size="icon" title="Delete Patient">
                            <Delete />
                          </Button>)}
                        {allowFinancial && (<Button variant="ghost" size="icon" onClick={() => {
                    setModalPatientId(Number(patient.id));
                    setIsFinancialsOpen(true);
                }} className="text-indigo-600 hover:text-indigo-800 hover:bg-indigo-50" title="View financials">
                            <FileCheck className="h-5 w-5"/>
                          </Button>)}
                        {allowEdit && (<Button variant="ghost" size="icon" onClick={() => {
                    handleEditPatient(patient);
                }} className="text-blue-600 hover:text-blue-800 hover:bg-blue-50" title="Edit Patient">
                            <Edit className="h-4 w-4"/>
                          </Button>)}
                        {allowNewClaim && (<Button variant="ghost" size="icon" onClick={() => onNewClaim?.(Number(patient.id))} className="text-green-600 hover:text-green-800 hover:bg-green-50" title="New Claim">
                            <FileCheck className="h-5 w-5"/>
                          </Button>)}
                        {allowView && (<Button variant="ghost" size="icon" onClick={() => {
                    handleViewPatient(patient);
                }} className="text-gray-600 hover:text-gray-800 hover:bg-gray-50" title="View Patient Info">
                            <Eye className="h-4 w-4"/>
                          </Button>)}
                      </div>
                    </TableCell>
                  </TableRow>
                </React.Fragment>)))}
          </TableBody>
        </Table>
      </div>

      {/* View Patient Modal */}
      <Dialog open={isViewPatientOpen} onOpenChange={setIsViewPatientOpen}>
        <DialogContent className="sm:max-w-[600px]">
          <DialogHeader>
            <DialogTitle>Patient Details</DialogTitle>
            <DialogDescription>
              Complete information about the patient.
            </DialogDescription>
          </DialogHeader>

          {currentPatient && (<div className="space-y-4">
              <div className="flex items-center space-x-4">
                <div className="h-16 w-16 rounded-full bg-primary text-white flex items-center justify-center text-xl font-medium">
                  {currentPatient.firstName.charAt(0)}
                  {currentPatient.lastName.charAt(0)}
                </div>
                <div>
                  <h3 className="text-xl font-semibold">
                    {currentPatient.firstName} {currentPatient.lastName}
                  </h3>
                  <p className="text-gray-500">
                    Patient ID: {currentPatient.id?.toString().padStart(4, "0")}
                  </p>
                </div>
              </div>

              <div className="grid grid-cols-1 md:grid-cols-2 gap-4 pt-4">
                <div>
                  <h4 className="font-medium text-gray-900">
                    Personal Information
                  </h4>
                  <div className="mt-2 space-y-2">
                    <p>
                      <span className="text-gray-500">Date of Birth:</span>{" "}
                      {formatDateToHumanReadable(currentPatient.dateOfBirth)}
                    </p>
                    <p>
                      <span className="text-gray-500">Gender:</span>{" "}
                      {currentPatient.gender.charAt(0).toUpperCase() +
                currentPatient.gender.slice(1)}
                    </p>
                    <p>
                      <span className="text-gray-500">Status:</span>{" "}
                      <span className={cn(currentPatient.status === "ACTIVE"
                ? "text-green-600"
                : currentPatient.status === "INACTIVE"
                    ? "text-red-600"
                    : currentPatient.status === "PLAN_NOT_ACCEPTED"
                        ? "text-amber-600"
                        : "text-gray-600", "font-medium")}>
                        {currentPatient.status === "PLAN_NOT_ACCEPTED"
                ? "Plan Not Accepted"
                : currentPatient.status
                    ? currentPatient.status.charAt(0).toUpperCase() +
                        currentPatient.status.slice(1).toLowerCase()
                    : "Unknown"}
                      </span>
                    </p>
                  </div>
                </div>

                <div>
                  <h4 className="font-medium text-gray-900">
                    Contact Information
                  </h4>
                  <div className="mt-2 space-y-2">
                    <p>
                      <span className="text-gray-500">Phone:</span>{" "}
                      {currentPatient.phone}
                    </p>
                    <p>
                      <span className="text-gray-500">Email:</span>{" "}
                      {currentPatient.email || "N/A"}
                    </p>
                    <p>
                      <span className="text-gray-500">Address:</span>{" "}
                      {currentPatient.address ? (<>
                          {currentPatient.address}
                          {currentPatient.city && `, ${currentPatient.city}`}
                          {currentPatient.zipCode &&
                    ` ${currentPatient.zipCode}`}
                        </>) : ("N/A")}
                    </p>
                  </div>
                </div>

                <div>
                  <h4 className="font-medium text-gray-900">Insurance</h4>
                  <div className="mt-2 space-y-2">
                    <p>
                      <span className="text-gray-500">Provider:</span>{" "}
                      {currentPatient.insuranceProvider
                ? currentPatient.insuranceProvider === "delta"
                    ? "Delta Dental"
                    : currentPatient.insuranceProvider === "metlife"
                        ? "MetLife"
                        : currentPatient.insuranceProvider === "cigna"
                            ? "Cigna"
                            : currentPatient.insuranceProvider === "aetna"
                                ? "Aetna"
                                : currentPatient.insuranceProvider
                : "N/A"}
                    </p>
                    <p>
                      <span className="text-gray-500">ID:</span>{" "}
                      {currentPatient.insuranceId || "N/A"}
                    </p>
                    <p>
                      <span className="text-gray-500">Group Number:</span>{" "}
                      {currentPatient.groupNumber || "N/A"}
                    </p>
                    <p>
                      <span className="text-gray-500">Policy Holder:</span>{" "}
                      {currentPatient.policyHolder || "Self"}
                    </p>
                  </div>
                </div>

                <div>
                  <h4 className="font-medium text-gray-900">
                    Medical Information
                  </h4>
                  <div className="mt-2 space-y-2">
                    <p>
                      <span className="text-gray-500">Allergies:</span>{" "}
                      {currentPatient.allergies || "None reported"}
                    </p>
                    <p>
                      <span className="text-gray-500">Medical Conditions:</span>{" "}
                      {currentPatient.medicalConditions || "None reported"}
                    </p>
                  </div>
                </div>
              </div>

              <div className="flex justify-end space-x-2 pt-4">
                <Button variant="outline" onClick={() => setIsViewPatientOpen(false)}>
                  Close
                </Button>
                <Button onClick={() => {
                setIsViewPatientOpen(false);
                handleEditPatient(currentPatient);
            }}>
                  Edit Patient
                </Button>
              </div>
            </div>)}
        </DialogContent>
      </Dialog>

      {/* Add/Edit Patient Modal */}
      <AddPatientModal open={isAddPatientOpen} onOpenChange={setIsAddPatientOpen} onSubmit={handleUpdatePatient} isLoading={isLoading} patient={currentPatient}/>

      {/* Financial Modal */}
      <PatientFinancialsModal patientId={modalPatientId} open={isFinancialsOpen} onOpenChange={(v) => {
            setIsFinancialsOpen(v);
            if (!v)
                setModalPatientId(null);
        }}/>

      <DeleteConfirmationDialog isOpen={isDeletePatientOpen} onConfirm={handleConfirmDeletePatient} onCancel={() => setIsDeletePatientOpen(false)} entityName={currentPatient?.firstName}/>

      {/* Pagination */}
      {totalPages > 1 && (<div className="bg-white px-4 py-3 border-t border-gray-200">
          <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between">
            <div className="text-sm text-muted-foreground mb-2 sm:mb-0 whitespace-nowrap">
              Showing {startItem}–{endItem} of {patientsData?.totalCount || 0}{" "}
              results
            </div>
            <Pagination>
              <PaginationContent>
                <PaginationItem>
                  <PaginationPrevious href="#" onClick={(e) => {
                e.preventDefault();
                if (currentPage > 1)
                    setCurrentPage(currentPage - 1);
            }} className={currentPage === 1 ? "pointer-events-none opacity-50" : ""}/>
                </PaginationItem>

                {getPageNumbers(currentPage, totalPages).map((page, idx) => (<PaginationItem key={idx}>
                    {page === "..." ? (<span className="px-2 text-gray-500">...</span>) : (<PaginationLink href="#" onClick={(e) => {
                        e.preventDefault();
                        setCurrentPage(page);
                    }} isActive={currentPage === page}>
                        {page}
                      </PaginationLink>)}
                  </PaginationItem>))}

                <PaginationItem>
                  <PaginationNext href="#" onClick={(e) => {
                e.preventDefault();
                if (currentPage < totalPages)
                    setCurrentPage(currentPage + 1);
            }} className={currentPage === totalPages
                ? "pointer-events-none opacity-50"
                : ""}/>
                </PaginationItem>
              </PaginationContent>
            </Pagination>
          </div>
        </div>)}

      {/* Document Viewer Modal */}
      <Dialog open={documentViewerOpen} onOpenChange={handleDocumentViewerClose}>
        <DialogContent className="sm:max-w-[50vw] sm:max-h-[90vh]">
          <DialogHeader className="flex flex-row items-center justify-between">
            <div className="flex flex-col">
              <DialogTitle>Document Viewer</DialogTitle>
              <DialogDescription>
                Viewing: {viewingDocument?.name}
              </DialogDescription>
            </div>
            <Button variant="ghost" size="icon" onClick={handleDocumentViewerClose} className="h-8 w-8 p-0">
              <X className="h-4 w-4"/>
            </Button>
          </DialogHeader>
          <div className="flex flex-col items-center justify-center min-h-[60vh]">
            {viewingDocument && (<>
                {viewingDocument.name.toLowerCase().endsWith('.pdf') ? (<iframe src={viewingDocument.url} className="w-full h-[60vh] border rounded" title={viewingDocument.name}/>) : viewingDocument.name.toLowerCase().match(/\.(jpg|jpeg|png|gif|webp)$/i) ? (<img src={viewingDocument.url} alt={viewingDocument.name} className="max-w-full max-h-[60vh] object-contain rounded"/>) : (<div className="text-center">
                    <FileText className="h-16 w-16 mx-auto text-gray-400 mb-4"/>
                    <p className="text-gray-600 mb-4">Preview not available for this file type</p>
                    <Button onClick={() => {
                    const link = document.createElement('a');
                    link.href = viewingDocument.url;
                    link.target = '_blank';
                    link.click();
                }} className="bg-blue-600 hover:bg-blue-700">
                      Open in New Tab
                    </Button>
                  </div>)}
              </>)}
          </div>
        </DialogContent>
      </Dialog>

      {/* Camera Modal */}
      <Dialog open={cameraOpen} onOpenChange={handleCameraClose}>
        <DialogContent className="p-0 border-none max-w-none w-full h-[100dvh] flex flex-col bg-black overflow-hidden sm:rounded-none">
          {/* Full screen container */}
          <div className="relative flex-1 flex flex-col overflow-hidden">

            {/* Close button at top-right */}
            <Button variant="ghost" size="icon" onClick={handleCameraClose} className="absolute top-4 right-4 z-50 h-10 w-10 p-0 text-white bg-black/40 hover:bg-black/60 rounded-full">
              <X className="h-6 w-6"/>
            </Button>

            {/* Camera/Image View */}
            <div className="relative flex-1 bg-black flex items-center justify-center overflow-hidden">
              {!capturedImage ? (<>
                  <video ref={videoRef} autoPlay playsInline className="w-full h-full object-cover"/>
                  <canvas ref={canvasRef} className="hidden"/>
                </>) : (<img src={capturedImage} alt="Captured" className="w-full h-full object-contain"/>)}
            </div>

            {/* Bottom Controls */}
            <div className="absolute bottom-10 left-0 right-0 px-8 flex items-center justify-center bg-transparent z-40">
              {!capturedImage ? (<div className="flex items-center justify-between w-full max-w-sm px-4">
                  {/* Camera Switch */}
                  <Button variant="ghost" size="icon" onClick={toggleFacingMode} className="h-12 w-12 text-white bg-white/20 hover:bg-white/40 rounded-full shadow-lg backdrop-blur-sm">
                    <RefreshCw className="h-6 w-6"/>
                  </Button>

                  {/* Capture Image Icon Button */}
                  <button onClick={capturePhoto} className="h-20 w-20 rounded-full border-4 border-white flex items-center justify-center bg-transparent active:scale-90 transition-all shadow-xl">
                    <div className="h-14 w-14 rounded-full bg-white flex items-center justify-center">
                      <Camera className="h-8 w-8 text-black"/>
                    </div>
                  </button>

                  {/* Spacer for symmetry */}
                  <div className="w-12"/>
                </div>) : (<div className="flex items-center gap-4 w-full max-w-md justify-center">
                  <Button variant="outline" onClick={retakePhoto} className="flex bg-white/10 text-white border-white/20 hover:bg-white/20 px-6 py-4 rounded-2xl font-semibold backdrop-blur-md">
                    Retake
                  </Button>
                  <Button onClick={saveCapturedPhoto} className="flex bg-white text-black hover:bg-gray-100 px-6 py-4 rounded-2xl font-semibold shadow-lg">
                    <Upload className="h-5 w-5 mr-2"/>
                    Save
                  </Button>
                </div>)}
            </div>
          </div>
        </DialogContent>
      </Dialog>
    </div>);
}
