import { useState, useRef, useCallback, useEffect } from 'react';
import './DragDropUpload.css';

const CHUNK_SIZE = 10 * 1024 * 1024;
const CHUNKED_UPLOAD_THRESHOLD = 100 * 1024 * 1024;
const UPLOAD_STATE_PREFIX = 'orchard_upload_';

interface StoredUploadState {
  uploadId: string;
  fileHash: string;
  filename: string;
  fileSize: number;
  completedParts: number[];
  project: string;
  package: string;
  createdAt: number;
}

function getUploadStateKey(project: string, pkg: string, fileHash: string): string {
  return `${UPLOAD_STATE_PREFIX}${project}_${pkg}_${fileHash}`;
}

function saveUploadState(state: StoredUploadState): void {
  try {
    const key = getUploadStateKey(state.project, state.package, state.fileHash);
    localStorage.setItem(key, JSON.stringify(state));
  } catch {
    // localStorage might be full or unavailable
  }
}

function loadUploadState(project: string, pkg: string, fileHash: string): StoredUploadState | null {
  try {
    const key = getUploadStateKey(project, pkg, fileHash);
    const stored = localStorage.getItem(key);
    if (!stored) return null;
    const state = JSON.parse(stored) as StoredUploadState;
    const oneDay = 24 * 60 * 60 * 1000;
    if (Date.now() - state.createdAt > oneDay) {
      localStorage.removeItem(key);
      return null;
    }
    return state;
  } catch {
    return null;
  }
}

function clearUploadState(project: string, pkg: string, fileHash: string): void {
  try {
    const key = getUploadStateKey(project, pkg, fileHash);
    localStorage.removeItem(key);
  } catch {
    // ignore
  }
}

// Types
export type UploadStatus = 'pending' | 'uploading' | 'complete' | 'failed' | 'validating' | 'paused';

export interface UploadItem {
  id: string;
  file: File;
  status: UploadStatus;
  progress: number;
  speed: number; // bytes per second
  error?: string;
  artifactId?: string;
  retryCount: number;
  startTime?: number;
}

export interface UploadResult {
  artifact_id: string;
  size: number;
  deduplicated?: boolean;
}

export interface DragDropUploadProps {
  projectName: string;
  packageName: string;
  onUploadComplete?: (results: UploadResult[]) => void;
  onUploadError?: (error: string) => void;
  allowedTypes?: string[]; // e.g., ['.tar.gz', '.zip', '.deb']
  allowAllTypes?: boolean;
  maxFileSize?: number; // in bytes
  maxConcurrentUploads?: number;
  maxRetries?: number;
  className?: string;
  disabled?: boolean;
  disabledReason?: string;
}

// Utility functions
function generateId(): string {
  return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}

function formatBytes(bytes: number): string {
  if (bytes === 0) return '0 B';
  const k = 1024;
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}

function formatSpeed(bytesPerSecond: number): string {
  return `${formatBytes(bytesPerSecond)}/s`;
}

function formatTimeRemaining(seconds: number): string {
  if (!isFinite(seconds) || seconds < 0) return '--:--';
  if (seconds < 60) return `${Math.round(seconds)}s`;
  if (seconds < 3600) return `${Math.floor(seconds / 60)}m ${Math.round(seconds % 60)}s`;
  return `${Math.floor(seconds / 3600)}h ${Math.floor((seconds % 3600) / 60)}m`;
}

function getFileExtension(filename: string): string {
  const parts = filename.toLowerCase().split('.');
  if (parts.length >= 3 && parts[parts.length - 2] === 'tar') {
    return `.${parts.slice(-2).join('.')}`;
  }
  return parts.length > 1 ? `.${parts[parts.length - 1]}` : '';
}

async function computeSHA256(file: File): Promise<string> {
  const buffer = await file.arrayBuffer();
  const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}

// Icons
function UploadIcon() {
  return (
    <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
      <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
      <polyline points="17 8 12 3 7 8" />
      <line x1="12" y1="3" x2="12" y2="15" />
    </svg>
  );
}

function CheckIcon() {
  return (
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
      <polyline points="20 6 9 17 4 12" />
    </svg>
  );
}

function ErrorIcon() {
  return (
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
      <circle cx="12" cy="12" r="10" />
      <line x1="15" y1="9" x2="9" y2="15" />
      <line x1="9" y1="9" x2="15" y2="15" />
    </svg>
  );
}

function RetryIcon() {
  return (
    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
      <polyline points="23 4 23 10 17 10" />
      <path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10" />
    </svg>
  );
}

function RemoveIcon() {
  return (
    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
      <line x1="18" y1="6" x2="6" y2="18" />
      <line x1="6" y1="6" x2="18" y2="18" />
    </svg>
  );
}

function FileIcon() {
  return (
    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
      <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
      <polyline points="14 2 14 8 20 8" />
    </svg>
  );
}

function PauseIcon() {
  return (
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
      <rect x="6" y="4" width="4" height="16" />
      <rect x="14" y="4" width="4" height="16" />
    </svg>
  );
}

function WifiOffIcon() {
  return (
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
      <line x1="1" y1="1" x2="23" y2="23" />
      <path d="M16.72 11.06A10.94 10.94 0 0 1 19 12.55" />
      <path d="M5 12.55a10.94 10.94 0 0 1 5.17-2.39" />
      <path d="M10.71 5.05A16 16 0 0 1 22.58 9" />
      <path d="M1.42 9a15.91 15.91 0 0 1 4.7-2.88" />
      <path d="M8.53 16.11a6 6 0 0 1 6.95 0" />
      <line x1="12" y1="20" x2="12.01" y2="20" />
    </svg>
  );
}

function SpinnerIcon() {
  return (
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className="spinner-icon">
      <circle cx="12" cy="12" r="10" strokeOpacity="0.25" />
      <path d="M12 2a10 10 0 0 1 10 10" />
    </svg>
  );
}

export function DragDropUpload({
  projectName,
  packageName,
  onUploadComplete,
  onUploadError,
  allowedTypes,
  allowAllTypes = true,
  maxFileSize,
  maxConcurrentUploads = 3,
  maxRetries = 3,
  className = '',
  disabled = false,
  disabledReason,
}: DragDropUploadProps) {
  const [isDragOver, setIsDragOver] = useState(false);
  const [uploadQueue, setUploadQueue] = useState<UploadItem[]>([]);
  const [isOnline, setIsOnline] = useState(navigator.onLine);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const dragCounterRef = useRef(0);
  const activeUploadsRef = useRef(0);
  const xhrMapRef = useRef<Map<string, XMLHttpRequest>>(new Map());

  // Online/Offline detection
  useEffect(() => {
    const handleOnline = () => {
      setIsOnline(true);
      // Resume paused uploads
      setUploadQueue(prev => prev.map(item => 
        item.status === 'paused' 
          ? { ...item, status: 'pending' as UploadStatus, error: undefined }
          : item
      ));
    };

    const handleOffline = () => {
      setIsOnline(false);
      // Pause uploading items and cancel their XHR requests
      setUploadQueue(prev => prev.map(item => {
        if (item.status === 'uploading') {
          // Abort the XHR request
          const xhr = xhrMapRef.current.get(item.id);
          if (xhr) {
            xhr.abort();
            xhrMapRef.current.delete(item.id);
          }
          return { ...item, status: 'paused' as UploadStatus, error: 'Network offline - will resume when connection is restored', progress: 0 };
        }
        if (item.status === 'pending') {
          return { ...item, status: 'paused' as UploadStatus, error: 'Network offline - waiting for connection' };
        }
        return item;
      }));
    };

    window.addEventListener('online', handleOnline);
    window.addEventListener('offline', handleOffline);

    return () => {
      window.removeEventListener('online', handleOnline);
      window.removeEventListener('offline', handleOffline);
    };
  }, []);

  // Validate a single file
  const validateFile = useCallback((file: File): string | null => {
    // Check file size
    if (maxFileSize && file.size > maxFileSize) {
      return `File exceeds ${formatBytes(maxFileSize)} limit`;
    }

    // Check file type if not allowing all types
    if (!allowAllTypes && allowedTypes && allowedTypes.length > 0) {
      const ext = getFileExtension(file.name);
      if (!allowedTypes.some(t => t.toLowerCase() === ext)) {
        return `File type ${ext || 'unknown'} not allowed. Accepted: ${allowedTypes.join(', ')}`;
      }
    }

    // Check for empty file
    if (file.size === 0) {
      return 'Cannot upload empty file';
    }

    return null;
  }, [allowedTypes, allowAllTypes, maxFileSize]);

  // Add files to queue
  const addFiles = useCallback((files: FileList | File[]) => {
    const newItems: UploadItem[] = Array.from(files).map(file => {
      const validationError = validateFile(file);
      return {
        id: generateId(),
        file,
        status: validationError ? 'failed' : 'pending',
        progress: 0,
        speed: 0,
        error: validationError || undefined,
        retryCount: 0,
      };
    });

    setUploadQueue(prev => [...prev, ...newItems]);
  }, [validateFile]);

  const uploadFileChunked = useCallback(async (item: UploadItem): Promise<UploadResult> => {
    setUploadQueue(prev => prev.map(u => 
      u.id === item.id 
        ? { ...u, status: 'validating' as UploadStatus, startTime: Date.now() }
        : u
    ));

    const fileHash = await computeSHA256(item.file);
    
    const storedState = loadUploadState(projectName, packageName, fileHash);
    let uploadId: string;
    let completedParts: number[] = [];

    if (storedState && storedState.fileSize === item.file.size && storedState.filename === item.file.name) {
      try {
        const statusResponse = await fetch(
          `/api/v1/project/${projectName}/${packageName}/upload/${storedState.uploadId}/status`
        );
        if (statusResponse.ok) {
          const statusData = await statusResponse.json();
          uploadId = storedState.uploadId;
          completedParts = statusData.uploaded_parts || [];
        } else {
          throw new Error('Stored upload no longer valid');
        }
      } catch {
        clearUploadState(projectName, packageName, fileHash);
        uploadId = await initNewUpload();
      }
    } else {
      uploadId = await initNewUpload();
    }

    async function initNewUpload(): Promise<string> {
      const initResponse = await fetch(
        `/api/v1/project/${projectName}/${packageName}/upload/init`,
        {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            expected_hash: fileHash,
            filename: item.file.name,
            size: item.file.size,
          }),
        }
      );

      if (!initResponse.ok) {
        const error = await initResponse.json().catch(() => ({}));
        throw new Error(error.detail || `Init failed: ${initResponse.status}`);
      }

      const initData = await initResponse.json();

      if (initData.already_exists) {
        throw { deduplicated: true, artifact_id: initData.artifact_id };
      }

      saveUploadState({
        uploadId: initData.upload_id,
        fileHash,
        filename: item.file.name,
        fileSize: item.file.size,
        completedParts: [],
        project: projectName,
        package: packageName,
        createdAt: Date.now(),
      });

      return initData.upload_id;
    }

    const totalChunks = Math.ceil(item.file.size / CHUNK_SIZE);
    let uploadedBytes = completedParts.length * CHUNK_SIZE;
    if (uploadedBytes > item.file.size) uploadedBytes = item.file.size - (item.file.size % CHUNK_SIZE);
    const startTime = Date.now();

    for (let partNumber = 1; partNumber <= totalChunks; partNumber++) {
      if (completedParts.includes(partNumber)) {
        continue;
      }

      if (!isOnline) {
        throw new Error('Network offline');
      }

      const start = (partNumber - 1) * CHUNK_SIZE;
      const end = Math.min(start + CHUNK_SIZE, item.file.size);
      const chunk = item.file.slice(start, end);

      const partResponse = await fetch(
        `/api/v1/project/${projectName}/${packageName}/upload/${uploadId}/part/${partNumber}`,
        {
          method: 'PUT',
          body: chunk,
        }
      );

      if (!partResponse.ok) {
        throw new Error(`Part ${partNumber} upload failed: ${partResponse.status}`);
      }

      completedParts.push(partNumber);
      saveUploadState({
        uploadId,
        fileHash,
        filename: item.file.name,
        fileSize: item.file.size,
        completedParts,
        project: projectName,
        package: packageName,
        createdAt: Date.now(),
      });

      uploadedBytes += chunk.size;
      const elapsed = (Date.now() - startTime) / 1000;
      const speed = elapsed > 0 ? uploadedBytes / elapsed : 0;
      const progress = Math.round((uploadedBytes / item.file.size) * 100);

      setUploadQueue(prev => prev.map(u => 
        u.id === item.id 
          ? { ...u, progress, speed, status: 'uploading' as UploadStatus }
          : u
      ));
    }

    const completeResponse = await fetch(
      `/api/v1/project/${projectName}/${packageName}/upload/${uploadId}/complete`,
      {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({}),
      }
    );

    if (!completeResponse.ok) {
      throw new Error(`Complete failed: ${completeResponse.status}`);
    }

    clearUploadState(projectName, packageName, fileHash);

    const completeData = await completeResponse.json();
    return {
      artifact_id: completeData.artifact_id,
      size: completeData.size,
      deduplicated: false,
    };
  }, [projectName, packageName, isOnline]);

  const uploadFileSimple = useCallback((item: UploadItem): Promise<UploadResult> => {
    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      xhrMapRef.current.set(item.id, xhr);

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

      let lastLoaded = 0;
      let lastTime = Date.now();

      xhr.upload.addEventListener('progress', (e) => {
        if (e.lengthComputable) {
          const now = Date.now();
          const timeDiff = (now - lastTime) / 1000;
          const loadedDiff = e.loaded - lastLoaded;
          
          const speed = timeDiff > 0 ? loadedDiff / timeDiff : 0;
          const progress = Math.round((e.loaded / e.total) * 100);

          setUploadQueue(prev => prev.map(u => 
            u.id === item.id 
              ? { ...u, progress, speed, status: 'uploading' as UploadStatus }
              : u
          ));

          lastLoaded = e.loaded;
          lastTime = now;
        }
      });

      xhr.addEventListener('load', () => {
        xhrMapRef.current.delete(item.id);
        if (xhr.status >= 200 && xhr.status < 300) {
          try {
            const result = JSON.parse(xhr.responseText) as UploadResult;
            resolve(result);
          } catch {
            reject(new Error('Invalid response from server'));
          }
        } else {
          try {
            const error = JSON.parse(xhr.responseText);
            reject(new Error(error.detail || `Upload failed: ${xhr.status}`));
          } catch {
            reject(new Error(`Upload failed: ${xhr.status}`));
          }
        }
      });

      xhr.addEventListener('error', () => {
        xhrMapRef.current.delete(item.id);
        reject(new Error('Network error - check your connection'));
      });

      xhr.addEventListener('timeout', () => {
        xhrMapRef.current.delete(item.id);
        reject(new Error('Upload timed out'));
      });

      xhr.addEventListener('abort', () => {
        xhrMapRef.current.delete(item.id);
        reject(new Error('Upload cancelled'));
      });

      xhr.open('POST', `/api/v1/project/${projectName}/${packageName}/upload`);
      xhr.timeout = 300000;
      xhr.send(formData);

      setUploadQueue(prev => prev.map(u =>
        u.id === item.id
          ? { ...u, status: 'uploading' as UploadStatus, startTime: Date.now() }
          : u
      ));
    });
  }, [projectName, packageName]);

  const uploadFile = useCallback((item: UploadItem): Promise<UploadResult> => {
    if (item.file.size >= CHUNKED_UPLOAD_THRESHOLD) {
      return uploadFileChunked(item);
    }
    return uploadFileSimple(item);
  }, [uploadFileChunked, uploadFileSimple]);

  const processQueue = useCallback(async () => {
    if (!isOnline) return;
    
    const pendingItems = uploadQueue.filter(item => item.status === 'pending');
    
    for (const item of pendingItems) {
      if (activeUploadsRef.current >= maxConcurrentUploads) {
        break;
      }

      activeUploadsRef.current++;

      // Start upload
      setUploadQueue(prev => prev.map(u => 
        u.id === item.id ? { ...u, status: 'uploading' as UploadStatus } : u
      ));

      try {
        const result = await uploadFile(item);
        
        setUploadQueue(prev => prev.map(u => 
          u.id === item.id 
            ? { ...u, status: 'complete' as UploadStatus, progress: 100, artifactId: result.artifact_id }
            : u
        ));
      } catch (err: unknown) {
        const dedupErr = err as { deduplicated?: boolean; artifact_id?: string };
        if (dedupErr.deduplicated && dedupErr.artifact_id) {
          setUploadQueue(prev => prev.map(u => 
            u.id === item.id 
              ? { ...u, status: 'complete' as UploadStatus, progress: 100, artifactId: dedupErr.artifact_id }
              : u
          ));
        } else {
          const errorMessage = err instanceof Error ? err.message : 'Upload failed';
          const shouldRetry = item.retryCount < maxRetries && 
            (errorMessage.includes('Network') || errorMessage.includes('timeout'));

          if (shouldRetry) {
            const delay = Math.pow(2, item.retryCount) * 1000;
            setTimeout(() => {
              setUploadQueue(prev => prev.map(u => 
                u.id === item.id 
                  ? { ...u, status: 'pending' as UploadStatus, retryCount: u.retryCount + 1, progress: 0 }
                  : u
              ));
            }, delay);
          } else {
            setUploadQueue(prev => prev.map(u => 
              u.id === item.id 
                ? { ...u, status: 'failed' as UploadStatus, error: errorMessage }
                : u
            ));
            onUploadError?.(errorMessage);
          }
        }
      } finally {
        activeUploadsRef.current--;
      }
    }
  }, [uploadQueue, maxConcurrentUploads, maxRetries, uploadFile, onUploadError, isOnline]);

  useEffect(() => {
    const hasPending = uploadQueue.some(item => item.status === 'pending');
    if (hasPending && activeUploadsRef.current < maxConcurrentUploads && isOnline) {
      processQueue();
    }

    const allComplete = uploadQueue.length > 0 && 
      uploadQueue.every(item => item.status === 'complete' || item.status === 'failed');
    
    if (allComplete) {
      const completedResults = uploadQueue
        .filter(item => item.status === 'complete' && item.artifactId)
        .map(item => ({
          artifact_id: item.artifactId!,
          size: item.file.size,
        }));
      
      if (completedResults.length > 0) {
        onUploadComplete?.(completedResults);
      }
    }
  }, [uploadQueue, maxConcurrentUploads, processQueue, onUploadComplete, isOnline]);

  // Drag event handlers
  const handleDragEnter = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    if (disabled) return;
    dragCounterRef.current++;
    if (e.dataTransfer.items && e.dataTransfer.items.length > 0) {
      setIsDragOver(true);
    }
  }, [disabled]);

  const handleDragLeave = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    if (disabled) return;
    dragCounterRef.current--;
    if (dragCounterRef.current === 0) {
      setIsDragOver(false);
    }
  }, [disabled]);

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

  const handleDrop = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDragOver(false);
    dragCounterRef.current = 0;

    if (disabled) return;

    const files = e.dataTransfer.files;
    if (files && files.length > 0) {
      addFiles(files);
    }
  }, [addFiles, disabled]);

  // Click to browse
  const handleClick = useCallback(() => {
    if (disabled) return;
    fileInputRef.current?.click();
  }, [disabled]);

  const handleFileChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    if (disabled) return;
    const files = e.target.files;
    if (files && files.length > 0) {
      addFiles(files);
    }
    // Reset input so same file can be selected again
    if (fileInputRef.current) {
      fileInputRef.current.value = '';
    }
  }, [addFiles, disabled]);

  // Remove item from queue
  const removeItem = useCallback((id: string) => {
    setUploadQueue(prev => prev.filter(item => item.id !== id));
  }, []);

  // Retry failed upload
  const retryItem = useCallback((id: string) => {
    setUploadQueue(prev => prev.map(item => 
      item.id === id 
        ? { ...item, status: 'pending' as UploadStatus, error: undefined, progress: 0, retryCount: 0 }
        : item
    ));
  }, []);

  // Clear completed/failed items
  const clearCompleted = useCallback(() => {
    setUploadQueue(prev => prev.filter(item => 
      item.status !== 'complete' && item.status !== 'failed'
    ));
  }, []);

  // Calculate overall progress
  const overallProgress = uploadQueue.length > 0
    ? Math.round(uploadQueue.reduce((sum, item) => sum + item.progress, 0) / uploadQueue.length)
    : 0;

  const completedCount = uploadQueue.filter(item => item.status === 'complete').length;
  const failedCount = uploadQueue.filter(item => item.status === 'failed').length;
  const uploadingCount = uploadQueue.filter(item => item.status === 'uploading').length;
  const pausedCount = uploadQueue.filter(item => item.status === 'paused').length;

  return (
    <div className={`drag-drop-upload ${className}`}>
      {!isOnline && (
        <div className="offline-banner">
          <WifiOffIcon />
          <span>You're offline. Uploads will resume when connection is restored.</span>
        </div>
      )}

      <div
        className={`drop-zone ${isDragOver ? 'drop-zone--active' : ''} ${disabled ? 'drop-zone--disabled' : ''}`}
        onDragEnter={handleDragEnter}
        onDragLeave={handleDragLeave}
        onDragOver={handleDragOver}
        onDrop={handleDrop}
        onClick={handleClick}
        role="button"
        tabIndex={disabled ? -1 : 0}
        onKeyDown={(e) => e.key === 'Enter' && handleClick()}
        aria-disabled={disabled}
        title={disabled ? disabledReason : undefined}
      >
        <input
          ref={fileInputRef}
          type="file"
          multiple
          onChange={handleFileChange}
          className="drop-zone__input"
          accept={!allowAllTypes && allowedTypes ? allowedTypes.join(',') : undefined}
          disabled={disabled}
        />
        <div className="drop-zone__content">
          <UploadIcon />
          <p className="drop-zone__text">
            {disabled ? (
              <span>{disabledReason || 'Upload disabled'}</span>
            ) : (
              <><strong>Drag files here</strong> or click to browse</>
            )}
          </p>
          {!disabled && (
            <p className="drop-zone__hint">
              {maxFileSize && `Max file size: ${formatBytes(maxFileSize)}`}
              {!allowAllTypes && allowedTypes && ` • Accepted: ${allowedTypes.join(', ')}`}
            </p>
          )}
        </div>
      </div>

      {/* Upload Queue */}
      {uploadQueue.length > 0 && (
        <div className="upload-queue">
          <div className="upload-queue__header">
            <span className="upload-queue__title">
              {pausedCount > 0 && !isOnline
                ? `${pausedCount} uploads paused (offline)`
                : uploadingCount > 0 
                  ? `Uploading ${uploadingCount} of ${uploadQueue.length} files`
                  : `${completedCount} of ${uploadQueue.length} files uploaded`
              }
              {failedCount > 0 && ` (${failedCount} failed)`}
            </span>
            {(completedCount > 0 || failedCount > 0) && (
              <button 
                className="upload-queue__clear" 
                onClick={clearCompleted}
                type="button"
              >
                Clear finished
              </button>
            )}
          </div>

          {/* Overall progress bar */}
          {uploadingCount > 0 && (
            <div className="upload-queue__overall">
              <div className="progress-bar">
                <div 
                  className="progress-bar__fill" 
                  style={{ width: `${overallProgress}%` }}
                />
              </div>
              <span className="progress-bar__text">{overallProgress}%</span>
            </div>
          )}

          {/* Individual file items */}
          <ul className="upload-queue__list">
            {uploadQueue.map(item => (
              <li key={item.id} className={`upload-item upload-item--${item.status}`}>
                <div className="upload-item__icon">
                  {item.status === 'complete' ? <CheckIcon /> : 
                   item.status === 'failed' ? <ErrorIcon /> : 
                   item.status === 'paused' ? <PauseIcon /> :
                   item.status === 'validating' ? <SpinnerIcon /> :
                   <FileIcon />}
                </div>
                
                <div className="upload-item__info">
                  <div className="upload-item__name" title={item.file.name}>
                    {item.file.name}
                  </div>
                  <div className="upload-item__meta">
                    <span className="upload-item__size">{formatBytes(item.file.size)}</span>
                    {item.status === 'uploading' && item.speed > 0 && (
                      <>
                        <span className="upload-item__speed">{formatSpeed(item.speed)}</span>
                        {item.startTime && (
                          <span className="upload-item__eta">
                            {formatTimeRemaining(
                              (item.file.size - (item.file.size * item.progress / 100)) / item.speed
                            )} remaining
                          </span>
                        )}
                      </>
                    )}
                    {item.status === 'complete' && item.artifactId && (
                      <span className="upload-item__artifact">
                        ID: {item.artifactId.substring(0, 12)}...
                      </span>
                    )}
                    {item.error && (
                      <span className="upload-item__error">{item.error}</span>
                    )}
                    {item.retryCount > 0 && item.status === 'uploading' && (
                      <span className="upload-item__retry-count">Retry {item.retryCount}</span>
                    )}
                    {item.status === 'validating' && (
                      <span className="upload-item__validating">Computing hash...</span>
                    )}
                  </div>
                  
                  {item.status === 'uploading' && (
                    <div className="progress-bar progress-bar--small">
                      <div 
                        className="progress-bar__fill" 
                        style={{ width: `${item.progress}%` }}
                      />
                    </div>
                  )}
                </div>

                <div className="upload-item__actions">
                  {(item.status === 'failed' || (item.status === 'paused' && isOnline)) && (
                    <button 
                      className="upload-item__btn upload-item__btn--retry"
                      onClick={() => retryItem(item.id)}
                      title="Retry upload"
                      type="button"
                    >
                      <RetryIcon />
                    </button>
                  )}
                  {(item.status === 'complete' || item.status === 'failed' || item.status === 'pending' || item.status === 'paused') && (
                    <button 
                      className="upload-item__btn upload-item__btn--remove"
                      onClick={() => removeItem(item.id)}
                      title="Remove"
                      type="button"
                    >
                      <RemoveIcon />
                    </button>
                  )}
                </div>
              </li>
            ))}
          </ul>
        </div>
      )}
    </div>
  );
}
