import { useState, useRef, useCallback, useEffect } from 'react';
import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card';
import { Progress } from '@/components/ui/progress';
import { Badge } from '@/components/ui/badge';
import { Alert, AlertDescription } from '@/components/ui/alert';
import { 
  Upload, 
  X, 
  Image as ImageIcon, 
  AlertCircle, 
  Camera,
  FileImage
} from 'lucide-react';
import { cn } from '@/lib/utils';
import { getErrorMessage } from '@/lib/errorHandler';
import { supabase } from '@/integrations/supabase/client';
import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
import { useAuth } from '@/hooks/useAuth';
import { logger } from '@/lib/logger';

interface PhotoUploadProps {
  onUploadComplete?: (urls: string[], imageId?: string) => void;
  onUploadStart?: () => void;
  onError?: (error: string) => void;
  maxFiles?: number;
  existingPhotos?: string[];
  className?: string;
  variant?: 'default' | 'compact' | 'avatar';
  accept?: string;
  currentImageId?: string; // For cleanup of existing image
  maxSizeMB?: number; // Custom max file size in MB
}

interface UploadedImage {
  id: string;
  url: string;
  filename: string;
  thumbnailUrl: string;
  previewUrl?: string;
}

export function PhotoUpload({
  onUploadComplete,
  onUploadStart,
  onError,
  maxFiles = 5,
  existingPhotos = [],
  className,
  variant = 'default',
  accept = 'image/jpeg,image/png,image/webp',
  currentImageId,
  maxSizeMB = 10 // Default 10MB, but can be overridden
}: PhotoUploadProps) {
  const [uploadedImages, setUploadedImages] = useState<UploadedImage[]>([]);
  const [uploading, setUploading] = useState(false);
  const [uploadProgress, setUploadProgress] = useState(0);
  const [dragOver, setDragOver] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const objectUrlsRef = useRef<Set<string>>(new Set());

  const isAvatar = variant === 'avatar';
  const isCompact = variant === 'compact';
  const actualMaxFiles = isAvatar ? 1 : maxFiles;
  const totalImages = uploadedImages.length + existingPhotos.length;
  const canUploadMore = totalImages < actualMaxFiles;

  useEffect(() => {
      return () => {
        objectUrlsRef.current.forEach(url => {
          try {
            URL.revokeObjectURL(url);
          } catch (error: unknown) {
            logger.error('Failed to revoke object URL', { error: getErrorMessage(error) });
          }
        });
        objectUrlsRef.current.clear();
      };
    }, []);

  const createObjectUrl = (file: File): string => {
    const url = URL.createObjectURL(file);
    objectUrlsRef.current.add(url);
    return url;
  };

  const revokeObjectUrl = (url: string) => {
    if (objectUrlsRef.current.has(url)) {
      try {
        URL.revokeObjectURL(url);
        objectUrlsRef.current.delete(url);
      } catch (error: unknown) {
        logger.error('Failed to revoke object URL', { error: getErrorMessage(error) });
      }
    }
  };

  const validateFile = (file: File): string | null => {
    // Check file size using configurable limit
    const maxSize = maxSizeMB * 1024 * 1024;
    if (file.size > maxSize) {
      return `File size must be less than ${maxSizeMB}MB`;
    }

    // Check file type
    const allowedTypes = ['image/jpeg', 'image/png', 'image/webp'];
    if (!allowedTypes.includes(file.type)) {
      return 'Only JPEG, PNG, and WebP images are allowed';
    }

    return null;
  };

  const uploadFile = async (file: File, previewUrl: string): Promise<UploadedImage> => {
    try {
      const { data: uploadData, error: uploadError, requestId } = await invokeWithTracking(
        'upload-image',
        { 
          metadata: {
            filename: file.name,
            size: file.size,
            type: file.type,
            uploadedAt: new Date().toISOString()
          },
          variant: isAvatar ? 'avatar' : 'public'
        },
        undefined
      );

      if (uploadError) {
        revokeObjectUrl(previewUrl);
        throw new Error(uploadError.message);
      }

      if (!uploadData?.success) {
        revokeObjectUrl(previewUrl);
        throw new Error(uploadData?.error || 'Failed to get upload URL');
      }

      const { uploadURL, id } = uploadData;

      const formData = new FormData();
      formData.append('file', file);

      const uploadResponse = await fetch(uploadURL, {
        method: 'POST',
        body: formData,
      });

      if (!uploadResponse.ok) {
        revokeObjectUrl(previewUrl);
        throw new Error('Direct upload to Cloudflare failed');
      }

      // Fetch session token once before polling
      const sessionData = await supabase.auth.getSession();
      const accessToken = sessionData.data.session?.access_token;
      
      if (!accessToken) {
        revokeObjectUrl(previewUrl);
        throw new Error('Authentication required for upload');
      }

      const maxAttempts = 60;
      let attempts = 0;
      const supabaseUrl = import.meta.env.VITE_SUPABASE_URL || 'https://ydvtmnrszybqnbcqbdcy.supabase.co';
      
      while (attempts < maxAttempts) {
        try {
          const response = await fetch(`${supabaseUrl}/functions/v1/upload-image?id=${encodeURIComponent(id)}`, {
            method: 'GET',
            headers: {
              'Authorization': `Bearer ${accessToken}`,
              'Content-Type': 'application/json'
            }
          });
          
          if (response.ok) {
            const statusData = await response.json();
            
            if (statusData?.success && statusData.uploaded && statusData.urls) {
              const imageUrl = isAvatar ? statusData.urls.avatar : statusData.urls.public;
              const thumbUrl = isAvatar ? statusData.urls.avatar : statusData.urls.thumbnail;
              
              revokeObjectUrl(previewUrl);
              
              return {
                id: statusData.id,
                url: imageUrl,
                filename: file.name,
                thumbnailUrl: thumbUrl,
                previewUrl: undefined
              };
            }
          }
        } catch (error: unknown) {
          logger.error('Status poll error', { error: getErrorMessage(error) });
        }

        await new Promise(resolve => setTimeout(resolve, 500));
        attempts++;
      }

      revokeObjectUrl(previewUrl);
      throw new Error('Upload timeout - image processing took too long');
    } catch (error: unknown) {
      revokeObjectUrl(previewUrl);
      throw error;
    }
  };

  const handleFiles = async (files: FileList) => {
    if (!isAvatar && !canUploadMore) {
      setError(`Maximum ${actualMaxFiles} ${actualMaxFiles === 1 ? 'image' : 'images'} allowed`);
      onError?.(`Maximum ${actualMaxFiles} ${actualMaxFiles === 1 ? 'image' : 'images'} allowed`);
      return;
    }

    const filesToUpload = isAvatar ? Array.from(files).slice(0, 1) : Array.from(files).slice(0, actualMaxFiles - totalImages);
    
    if (filesToUpload.length === 0) {
      setError('No files to upload');
      onError?.('No files to upload');
      return;
    }
    
    for (const file of filesToUpload) {
      const validationError = validateFile(file);
      if (validationError) {
        setError(validationError);
        onError?.(validationError);
        return;
      }
    }

    setUploading(true);
    setError(null);
    onUploadStart?.();

    const previewUrls: string[] = [];

    try {
      if (isAvatar && currentImageId) {
        try {
          await invokeWithTracking(
            'upload-image',
            { imageId: currentImageId },
            undefined,
            'DELETE'
          );
        } catch (deleteError) {
          logger.warn('Failed to delete old avatar');
        }
      }

      const uploadPromises = filesToUpload.map(async (file, index) => {
        setUploadProgress((index / filesToUpload.length) * 100);
        const previewUrl = createObjectUrl(file);
        previewUrls.push(previewUrl);
        return uploadFile(file, previewUrl);
      });

      const results = await Promise.all(uploadPromises);
      
      if (isAvatar) {
        setUploadedImages(results);
        onUploadComplete?.(results.map(img => img.url), results[0]?.id);
      } else {
        setUploadedImages(prev => [...prev, ...results]);
        const allUrls = [...existingPhotos, ...uploadedImages.map(img => img.url), ...results.map(img => img.url)];
        onUploadComplete?.(allUrls);
      }
      
      setUploadProgress(100);
    } catch (error: unknown) {
      previewUrls.forEach(url => revokeObjectUrl(url));
      const errorMsg = getErrorMessage(error);
      setError(errorMsg);
      onError?.(errorMsg);
    } finally {
      setUploading(false);
      setUploadProgress(0);
    }
  };

  const removeImage = (imageId: string) => {
    const imageToRemove = uploadedImages.find(img => img.id === imageId);
    if (imageToRemove?.previewUrl) {
      revokeObjectUrl(imageToRemove.previewUrl);
    }
    
    setUploadedImages(prev => prev.filter(img => img.id !== imageId));
    const updatedUrls = [...existingPhotos, ...uploadedImages.filter(img => img.id !== imageId).map(img => img.url)];
    onUploadComplete?.(updatedUrls);
  };

  const handleDragOver = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    setDragOver(true);
  }, []);

  const handleDragLeave = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    setDragOver(false);
  }, []);

  const handleDrop = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    setDragOver(false);
    
    if (!(isAvatar || canUploadMore) || uploading) return;
    
    const files = e.dataTransfer.files;
    if (files.length > 0) {
      handleFiles(files);
    }
  }, [canUploadMore, uploading]);

  const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = e.target.files;
    if (files && files.length > 0) {
      handleFiles(files);
    }
  };

  const triggerFileSelect = () => {
    fileInputRef.current?.click();
  };

  if (isAvatar) {
    return (
      <div className={cn('space-y-4', className)}>
        <div className="flex items-center gap-4">
          <div className="relative">
            {uploadedImages.length > 0 ? (
              <img 
                src={uploadedImages[0].thumbnailUrl} 
                alt="Avatar"
                className="w-24 h-24 rounded-full object-cover border-2 border-border"
                onError={(e) => {
                  logger.warn('Failed to load avatar image');
                  e.currentTarget.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBmaWxsPSIjZjNmNGY2Ii8+CjxwYXRoIGQ9Im0xNSAxMi0zLTMtMy4wMDEgM0w2IDlsNi02aDZ2NloiIGZpbGw9IiM5Y2EzYWYiLz4KPC9zdmc+';
                }}
              />
            ) : existingPhotos.length > 0 ? (
              <img
                src={existingPhotos[0]} 
                alt="Avatar"
                className="w-24 h-24 rounded-full object-cover border-2 border-border"
              />
            ) : (
              <div className="w-24 h-24 rounded-full bg-muted border-2 border-border flex items-center justify-center">
                <Camera className="w-8 h-8 text-muted-foreground" />
              </div>
            )}
            
            {uploading && (
              <div className="absolute inset-0 bg-background/80 rounded-full flex items-center justify-center">
                <Progress value={uploadProgress} className="w-16" />
              </div>
            )}
          </div>
          
          <div className="space-y-2">
            <Button 
              onClick={triggerFileSelect} 
              variant="outline" 
              size="sm"
              disabled={uploading}
            >
              <Upload className="w-4 h-4 mr-2" />
              {uploadedImages.length > 0 || existingPhotos.length > 0 ? 'Change Avatar' : 'Upload Avatar'}
            </Button>
            <p className="text-xs text-muted-foreground">
              JPEG, PNG, WebP up to {maxSizeMB}MB
            </p>
          </div>
        </div>

        <input
          ref={fileInputRef}
          type="file"
          accept={accept}
          onChange={handleFileSelect}
          className="hidden"
        />

        {error && (
          <Alert variant="destructive">
            <AlertCircle className="h-4 w-4" />
            <AlertDescription>{error}</AlertDescription>
          </Alert>
        )}
      </div>
    );
  }

  return (
    <div className={cn('space-y-4', className)}>
      {/* Upload Area */}
      <Card 
        className={cn(
          'border-2 border-dashed transition-colors cursor-pointer',
          dragOver && 'border-primary bg-primary/5',
          !(isAvatar || canUploadMore) && 'opacity-50 cursor-not-allowed',
          isCompact && 'p-2'
        )}
        onDragOver={handleDragOver}
        onDragLeave={handleDragLeave}
        onDrop={handleDrop}
        onClick={isAvatar || (canUploadMore && !uploading) ? triggerFileSelect : undefined}
      >
        <CardContent className={cn('p-8 text-center', isCompact && 'p-4')}>
          {uploading ? (
            <div className="space-y-4">
              <div className="animate-pulse">
                <Upload className="w-8 h-8 text-primary mx-auto" />
              </div>
              <div className="space-y-2">
                <p className="text-sm font-medium">Uploading...</p>
                <Progress value={uploadProgress} className="w-full" />
              </div>
            </div>
          ) : (
            <div className="space-y-4">
              <div className="flex items-center justify-center">
                {dragOver ? (
                  <FileImage className="w-12 h-12 text-primary" />
                ) : (
                  <ImageIcon className="w-12 h-12 text-muted-foreground" />
                )}
              </div>
              
              <div className="space-y-2">
                <p className="text-lg font-medium">
                  {isAvatar ? 'Upload Avatar' : canUploadMore ? 'Upload Photos' : 'Maximum Photos Reached'}
                </p>
                <p className="text-sm text-muted-foreground">
                  {isAvatar ? (
                    <>Drag & drop or click to browse<br />JPEG, PNG, WebP up to {maxSizeMB}MB</>
                  ) : canUploadMore ? (
                    <>Drag & drop or click to browse<br />JPEG, PNG, WebP up to {maxSizeMB}MB each</>
                  ) : (
                    `Maximum ${actualMaxFiles} ${actualMaxFiles === 1 ? 'photo' : 'photos'} allowed`
                  )}
                </p>
              </div>

              {!isAvatar && canUploadMore && (
                <Badge variant="outline">
                  {totalImages}/{actualMaxFiles} {actualMaxFiles === 1 ? 'photo' : 'photos'}
                </Badge>
              )}
            </div>
          )}
        </CardContent>
      </Card>

      <input
        ref={fileInputRef}
        type="file"
        accept={accept}
        multiple={maxFiles > 1}
        onChange={handleFileSelect}
        className="hidden"
        disabled={!(isAvatar || canUploadMore) || uploading}
      />

      {/* Error Display */}
      {error && (
        <Alert variant="destructive">
          <AlertCircle className="h-4 w-4" />
          <AlertDescription>{error}</AlertDescription>
        </Alert>
      )}

      {/* Uploaded Images Preview */}
      {uploadedImages.length > 0 && (
        <div className="space-y-2">
          <h4 className="text-sm font-medium">Uploaded Photos</h4>
          <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
            {uploadedImages.map((image) => (
              <div key={image.id} className="relative group">
                <img 
                  src={image.thumbnailUrl} 
                  alt={image.filename}
                  className="w-full aspect-square object-cover rounded-lg border"
                  onError={(e) => {
                    logger.warn('Failed to load thumbnail image');
                    e.currentTarget.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBmaWxsPSIjZjNmNGY2Ii8+CjxwYXRoIGQ9Im0xNSAxMi0zLTMtMy4wMDEgM0w2IDlsNi02aDZ2NloiIGZpbGw9IiM5Y2EzYWYiLz4KPC9zdmc+';
                  }}
                />
                <Button
                  variant="destructive"
                  size="icon"
                  className="absolute -top-2 -right-2 w-6 h-6 opacity-0 group-hover:opacity-100 transition-opacity"
                  onClick={() => removeImage(image.id)}
                >
                  <X className="w-3 h-3" />
                </Button>
                <div className="absolute bottom-2 left-2 right-2">
                  <Badge variant="secondary" className="text-xs truncate">
                    {image.filename}
                  </Badge>
                </div>
              </div>
            ))}
          </div>
        </div>
      )}

      {/* Existing Photos Display */}
      {existingPhotos.length > 0 && (
        <div className="space-y-2">
          <h4 className="text-sm font-medium">Existing Photos</h4>
          <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
            {existingPhotos.map((url, index) => (
              <div key={index} className="relative">
                <img 
                  src={url} 
                  alt={`Existing photo ${index + 1}`}
                  className="w-full aspect-square object-cover rounded-lg border"
                  onError={(e) => {
                    console.error('Failed to load existing image:', url);
                    e.currentTarget.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBmaWxsPSIjZjNmNGY2Ii8+CjxwYXRoIGQ9Im0xNSAxMi0zLTMtMy4wMDEgM0w2IDlsNi02aDZ2NloiIGZpbGw9IiM5Y2EzYWYiLz4KPC9zdmc+';
                  }}
                />
                <Badge variant="outline" className="absolute bottom-2 left-2 text-xs">
                  Existing
                </Badge>
              </div>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}
