import React, { useState, useCallback, useEffect } from 'react';
import {
  Box,
  Card,
  CardContent,
  Typography,
  Button,
  LinearProgress,
  Chip,
  List,
  ListItem,
  ListItemIcon,
  ListItemText,
  ListItemSecondaryAction,
  IconButton,
  Alert,
  Paper,
  alpha,
  useTheme,
  Divider,
} from '@mui/material';
import {
  CloudUpload as UploadIcon,
  InsertDriveFile as FileIcon,
  CheckCircle as CheckIcon,
  Error as ErrorIcon,
  Delete as DeleteIcon,
  Refresh as RefreshIcon,
} from '@mui/icons-material';
import { useDropzone, FileRejection, DropzoneOptions } from 'react-dropzone';
import { useNavigate } from 'react-router-dom';
import api from '../../services/api';
import { useNotifications } from '../../contexts/NotificationContext';
import LabelSelector from '../Labels/LabelSelector';
import { type LabelData } from '../Labels/Label';
import LanguageSelector from '../LanguageSelector';

interface UploadedDocument {
  id: string;
  original_filename: string;
  filename: string;
  file_size: number;
  mime_type: string;
  created_at: string;
}

interface FileItem {
  file: File;
  id: string;
  status: 'pending' | 'uploading' | 'success' | 'error';
  progress: number;
  error: string | null;
  documentId?: string;
}

interface UploadZoneProps {
  onUploadComplete?: (document: UploadedDocument) => void;
}

type FileStatus = 'pending' | 'uploading' | 'success' | 'error';

const UploadZone: React.FC<UploadZoneProps> = ({ onUploadComplete }) => {
  const theme = useTheme();
  const navigate = useNavigate();
  const { addBatchNotification } = useNotifications();
  const [files, setFiles] = useState<FileItem[]>([]);
  const [uploading, setUploading] = useState<boolean>(false);
  const [error, setError] = useState<string>('');
  const [selectedLabels, setSelectedLabels] = useState<LabelData[]>([]);
  const [availableLabels, setAvailableLabels] = useState<LabelData[]>([]);
  const [labelsLoading, setLabelsLoading] = useState<boolean>(false);
  const [selectedLanguages, setSelectedLanguages] = useState<string[]>(['eng']);
  const [primaryLanguage, setPrimaryLanguage] = useState<string>('eng');

  useEffect(() => {
    fetchLabels();
  }, []);

  const fetchLabels = async () => {
    try {
      setLabelsLoading(true);
      const response = await api.get('/labels?include_counts=false');
      
      if (response.status === 200 && Array.isArray(response.data)) {
        setAvailableLabels(response.data);
      } else {
        console.error('Failed to fetch labels:', response);
      }
    } catch (error) {
      console.error('Failed to fetch labels:', error);
    } finally {
      setLabelsLoading(false);
    }
  };

  const handleCreateLabel = async (labelData: Omit<LabelData, 'id' | 'is_system' | 'created_at' | 'updated_at' | 'document_count' | 'source_count'>) => {
    try {
      const response = await api.post('/labels', labelData);
      const newLabel = response.data;
      setAvailableLabels(prev => [...prev, newLabel]);
      return newLabel;
    } catch (error) {
      console.error('Failed to create label:', error);
      throw error;
    }
  };

  const handleLanguagesChange = (languages: string[], primary?: string) => {
    setSelectedLanguages(languages);
    if (primary) {
      setPrimaryLanguage(primary);
    } else if (languages.length > 0) {
      setPrimaryLanguage(languages[0]);
    }
  };

  const onDrop = useCallback((acceptedFiles: File[], rejectedFiles: FileRejection[]) => {
    setError('');
    
    // Handle rejected files
    if (rejectedFiles.length > 0) {
      const errors = rejectedFiles.map(file => 
        `${file.file.name}: ${file.errors.map(e => e.message).join(', ')}`
      );
      setError(`Some files were rejected: ${errors.join('; ')}`);
    }

    // Add accepted files to the list
    const newFiles: FileItem[] = acceptedFiles.map(file => ({
      file,
      id: Math.random().toString(36).substr(2, 9),
      status: 'pending' as FileStatus,
      progress: 0,
      error: null,
    }));

    setFiles(prev => [...prev, ...newFiles]);
  }, []);

  const dropzoneOptions: DropzoneOptions = {
    onDrop,
    accept: {
      'application/pdf': ['.pdf'],
      'image/*': ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.tiff'],
      'text/*': ['.txt', '.rtf'],
      'application/msword': ['.doc'],
      'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['.docx'],
    },
    maxSize: 50 * 1024 * 1024, // 50MB
    multiple: true,
  };

  const { getRootProps, getInputProps, isDragActive } = useDropzone(dropzoneOptions);

  const removeFile = (fileId: string): void => {
    setFiles(prev => prev.filter(f => f.id !== fileId));
  };

  const uploadFile = async (fileItem: FileItem): Promise<void> => {
    const formData = new FormData();
    formData.append('file', fileItem.file);
    
    // Add selected labels to the form data
    if (selectedLabels.length > 0) {
      const labelIds = selectedLabels.map(label => label.id);
      formData.append('label_ids', JSON.stringify(labelIds));
    }

    // Add selected languages to the form data
    if (selectedLanguages.length > 0) {
      selectedLanguages.forEach((lang, index) => {
        formData.append(`ocr_languages[${index}]`, lang);
      });
    }

    try {
      setFiles(prev => prev.map(f => 
        f.id === fileItem.id 
          ? { ...f, status: 'uploading' as FileStatus, progress: 0 }
          : f
      ));

      const response = await api.post<UploadedDocument>('/documents', formData, {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
        onUploadProgress: (progressEvent) => {
          if (progressEvent.total) {
            const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total);
            setFiles(prev => prev.map(f => 
              f.id === fileItem.id 
                ? { ...f, progress }
                : f
            ));
          }
        },
      });

      setFiles(prev => prev.map(f => 
        f.id === fileItem.id 
          ? { ...f, status: 'success' as FileStatus, progress: 100, documentId: response.data.id }
          : f
      ));

      if (onUploadComplete) {
        onUploadComplete(response.data);
      }
    } catch (error: any) {
      setFiles(prev => prev.map(f => 
        f.id === fileItem.id 
          ? { 
              ...f, 
              status: 'error' as FileStatus, 
              error: error.response?.data?.message || 'Upload failed',
              progress: 0,
            }
          : f
      ));
    }
  };

  const uploadAllFiles = async (): Promise<void> => {
    setUploading(true);
    setError('');

    const pendingFiles = files.filter(f => f.status === 'pending' || f.status === 'error');
    const results: { name: string; success: boolean }[] = [];
    
    try {
      await Promise.allSettled(pendingFiles.map(async (file) => {
        try {
          await uploadFile(file);
          results.push({ name: file.file.name, success: true });
        } catch (error) {
          results.push({ name: file.file.name, success: false });
        }
      }));
      
      // Trigger notification based on results
      const hasFailures = results.some(r => !r.success);
      const hasSuccesses = results.some(r => r.success);
      
      if (!hasFailures) {
        addBatchNotification('success', 'upload', results);
      } else if (!hasSuccesses) {
        addBatchNotification('error', 'upload', results);
      } else {
        addBatchNotification('warning', 'upload', results);
      }
    } catch (error) {
      setError('Upload failed. Please try again.');
    } finally {
      setUploading(false);
    }
  };

  const retryUpload = (fileItem: FileItem): void => {
    uploadFile(fileItem);
  };

  const clearCompleted = (): void => {
    setFiles(prev => prev.filter(f => f.status !== 'success'));
  };

  const formatFileSize = (bytes: number): string => {
    if (bytes === 0) return '0 Bytes';
    const k = 1024;
    const sizes = ['Bytes', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  };

  const getStatusColor = (status: FileStatus): string => {
    switch (status) {
      case 'success': return theme.palette.success.main;
      case 'error': return theme.palette.error.main;
      case 'uploading': return theme.palette.primary.main;
      default: return theme.palette.text.secondary;
    }
  };

  const getStatusIcon = (status: FileStatus): React.ReactElement => {
    switch (status) {
      case 'success': return <CheckIcon />;
      case 'error': return <ErrorIcon />;
      case 'uploading': return <UploadIcon />;
      default: return <FileIcon />;
    }
  };

  const handleFileClick = (fileItem: FileItem) => {
    if (fileItem.status === 'success' && fileItem.documentId) {
      navigate(`/documents/${fileItem.documentId}`);
    }
  };

  return (
    <Box>
      {/* Upload Drop Zone */}
      <Card 
        elevation={0}
        sx={{ 
          mb: 3,
          border: `2px dashed ${isDragActive ? theme.palette.primary.main : theme.palette.divider}`,
          backgroundColor: isDragActive ? alpha(theme.palette.primary.main, 0.04) : 'transparent',
          transition: 'all 0.2s ease-in-out',
        }}
      >
        <CardContent>
          <Box
            {...getRootProps()}
            sx={{
              textAlign: 'center',
              py: 6,
              cursor: 'pointer',
              outline: 'none',
            }}
          >
            <input {...getInputProps()} />
            
            <UploadIcon 
              sx={{ 
                fontSize: 64, 
                color: isDragActive ? 'primary.main' : 'text.secondary',
                mb: 2,
              }} 
            />
            
            <Typography variant="h6" sx={{ mb: 1, fontWeight: 600 }}>
              {isDragActive ? 'Drop files here' : 'Drag & drop files here'}
            </Typography>
            
            <Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
              or click to browse your computer
            </Typography>
            
            <Button 
              variant="contained" 
              sx={{ 
                mb: 2,
                borderRadius: 2,
                px: 3,
              }}
            >
              Choose Files
            </Button>
            
            <Box sx={{ display: 'flex', justifyContent: 'center', gap: 1, flexWrap: 'wrap' }}>
              <Chip label="PDF" size="small" variant="outlined" />
              <Chip label="Images" size="small" variant="outlined" />
              <Chip label="Text" size="small" variant="outlined" />
              <Chip label="Word" size="small" variant="outlined" />
            </Box>
            
            <Typography variant="caption" color="text.secondary" sx={{ display: 'block', mt: 2 }}>
              Maximum file size: 50MB per file
            </Typography>
          </Box>
        </CardContent>
      </Card>

      {/* Error Alert */}
      {error && (
        <Alert severity="error" sx={{ mb: 3, borderRadius: 2 }}>
          {error}
        </Alert>
      )}

      {/* Language Selection */}
      <Card elevation={0} sx={{ mb: 3 }}>
        <CardContent>
          <Typography variant="h6" sx={{ fontWeight: 600, mb: 2 }}>
            🌐 OCR Language Settings
          </Typography>
          <Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
            Select languages for optimal OCR text recognition
          </Typography>
          <Box sx={{ '& > div': { width: '100%' } }}>
            <LanguageSelector
              selectedLanguages={selectedLanguages}
              primaryLanguage={primaryLanguage}
              onLanguagesChange={handleLanguagesChange}
              disabled={uploading}
            />
          </Box>
        </CardContent>
      </Card>

      {/* Label Selection */}
      <Card elevation={0} sx={{ mb: 3 }}>
        <CardContent>
          <Typography variant="h6" sx={{ fontWeight: 600, mb: 2 }}>
            📋 Label Assignment
          </Typography>
          <Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
            Select labels to automatically assign to all uploaded documents
          </Typography>
          <LabelSelector
            selectedLabels={selectedLabels}
            availableLabels={availableLabels}
            onLabelsChange={setSelectedLabels}
            onCreateLabel={handleCreateLabel}
            placeholder="Choose labels for your documents..."
            size="medium"
            disabled={labelsLoading}
          />
          {selectedLabels.length > 0 && (
            <Typography variant="caption" color="text.secondary" sx={{ display: 'block', mt: 1 }}>
              These labels will be applied to all uploaded documents
            </Typography>
          )}
        </CardContent>
      </Card>

      {/* File List */}
      {files.length > 0 && (
        <Card elevation={0}>
          <CardContent>
            <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 }}>
              <Typography variant="h6" sx={{ fontWeight: 600 }}>
                Files ({files.length})
              </Typography>
              <Box sx={{ display: 'flex', gap: 1 }}>
                <Button
                  size="small"
                  onClick={clearCompleted}
                  disabled={!files.some(f => f.status === 'success')}
                >
                  Clear Completed
                </Button>
                <Button
                  variant="contained"
                  size="small"
                  onClick={uploadAllFiles}
                  disabled={uploading || !files.some(f => f.status === 'pending' || f.status === 'error')}
                  sx={{ borderRadius: 2 }}
                >
                  {uploading ? 'Uploading...' : 'Upload All'}
                </Button>
              </Box>
            </Box>

            <List sx={{ p: 0 }}>
              {files.map((fileItem, index) => (
                <ListItem 
                  key={fileItem.id}
                  sx={{ 
                    px: 0,
                    py: 2,
                    borderBottom: index < files.length - 1 ? 1 : 0,
                    borderColor: 'divider',
                    cursor: fileItem.status === 'success' && fileItem.documentId ? 'pointer' : 'default',
                    '&:hover': fileItem.status === 'success' && fileItem.documentId ? {
                      backgroundColor: alpha(theme.palette.primary.main, 0.04),
                    } : {},
                  }}
                  onClick={() => handleFileClick(fileItem)}
                >
                  <ListItemIcon>
                    <Box sx={{ color: getStatusColor(fileItem.status) }}>
                      {getStatusIcon(fileItem.status)}
                    </Box>
                  </ListItemIcon>
                  
                  <ListItemText
                    sx={{ 
                      pr: 6, // Add padding-right to prevent overlap with secondary action
                    }}
                    primary={
                      <Typography 
                        variant="subtitle2" 
                        sx={{ 
                          fontWeight: 500,
                          overflow: 'hidden',
                          textOverflow: 'ellipsis',
                          whiteSpace: 'nowrap',
                          maxWidth: '100%',
                        }}
                        title={fileItem.file.name}
                      >
                        {fileItem.file.name}
                      </Typography>
                    }
                    secondary={
                      <Box>
                        <Typography variant="caption" color="text.secondary">
                          {formatFileSize(fileItem.file.size)}
                        </Typography>
                        {fileItem.status === 'uploading' && (
                          <Box sx={{ mt: 1 }}>
                            <LinearProgress 
                              variant="determinate" 
                              value={fileItem.progress}
                              sx={{ height: 4, borderRadius: 2 }}
                            />
                            <Typography variant="caption" color="text.secondary">
                              {fileItem.progress}%
                            </Typography>
                          </Box>
                        )}
                        {fileItem.error && (
                          <Typography variant="caption" color="error" sx={{ display: 'block', mt: 0.5 }}>
                            {fileItem.error}
                          </Typography>
                        )}
                      </Box>
                    }
                  />
                  
                  <ListItemSecondaryAction>
                    <Box sx={{ display: 'flex', gap: 0.5 }}>
                      {fileItem.status === 'error' && (
                        <IconButton 
                          size="small" 
                          onClick={(e) => {
                            e.stopPropagation();
                            retryUpload(fileItem);
                          }}
                          sx={{ color: 'primary.main' }}
                        >
                          <RefreshIcon fontSize="small" />
                        </IconButton>
                      )}
                      <IconButton 
                        size="small" 
                        onClick={(e) => {
                          e.stopPropagation();
                          removeFile(fileItem.id);
                        }}
                        disabled={fileItem.status === 'uploading'}
                      >
                        <DeleteIcon fontSize="small" />
                      </IconButton>
                    </Box>
                  </ListItemSecondaryAction>
                </ListItem>
              ))}
            </List>
          </CardContent>
        </Card>
      )}
    </Box>
  );
};

export default UploadZone;