import requests
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render, redirect
from django.contrib import messages
from django.utils import timezone
from rest_framework.decorators import action
import logging
from rest_framework import viewsets
from ..models import LocalUploadedFile
from django.http import FileResponse
from django.contrib import messages 
import threading
import traceback
import os

logger = logging.getLogger(__name__)

class AdminDownloadViewSet(viewsets.ModelViewSet):
    @action(detail=False, methods=['get'], url_path=r'')
    def download_dashboard(self, request):
        base_domain = request.build_absolute_uri('/')
        try:
            from ..models import TransferOrder
            orders_needing_download = TransferOrder.objects.filter(
                status__in=['payment_completed', 'storage_selected']
            ).select_related('user').prefetch_related('file_selections').order_by('-created_at')
            downloading_orders = TransferOrder.objects.filter(
                status__in=['download_in_progress', 'processing']
            ).select_related('user').prefetch_related('file_selections').order_by('-updated_at')
            completed_orders = TransferOrder.objects.filter(
                status__in=['download_completed', 'completed']
            ).select_related('user').prefetch_related('file_selections').order_by('-updated_at')
            failed_orders = TransferOrder.objects.filter(
                status__in=['download_failed', 'download_partial', 'cancelled']
            ).select_related('user').prefetch_related('file_selections').order_by('-updated_at')
            context = {
                'base_domain': base_domain,
                'user': request.user,
                'orders_needing_download': orders_needing_download,
                'downloading_orders': downloading_orders,
                'completed_orders': completed_orders,
                'failed_orders': failed_orders,
                'total_pending': orders_needing_download.count(),
                'total_downloading': downloading_orders.count(),
                'total_completed': completed_orders.count(),
                'total_failed': failed_orders.count(),
            }
            return render(request, 'admin_download_dashboard.html', context)
        except Exception as e:
            messages.error(request, f"Failed to load dashboard: {str(e)}")
            return redirect(f'{base_domain}admin/')

    @action(detail=False, methods=['post'], url_path=r'')
    def download_selected_files(self, request):
        logger.info("File download request started", extra={
            'user': str(request.user),
            'method': request.method,
            'path': request.path,
            'is_ajax': 'HTTP_X_REQUESTED_WITH' in request.META
        })
        requested_with = request.META.get('HTTP_X_REQUESTED_WITH', '')
        is_ajax = requested_with.lower() == 'xmlhttprequest'
        logger.info(f"Request type detected: {'AJAX' if is_ajax else 'FORM SUBMISSION'}")
        try:
            order_id = request.POST.get('order_id')
            file_ids = request.POST.getlist('file_ids[]')
            logger.info("Download request parameters", extra={
                'order_id': order_id,
                'file_ids_count': len(file_ids),
                'file_ids': file_ids
            })
            if not order_id:
                error_msg = "Missing order_id in request"
                logger.error(error_msg, extra={'request_data': dict(request.POST)})
                if is_ajax:
                    return JsonResponse({'error': error_msg}, status=400)
                else:
                    messages.error(request, error_msg)
                    return redirect('download-dashboard')
            from ..models import TransferOrder
            try:
                order = TransferOrder.objects.get(id=order_id)
                logger.info(f"TransferOrder found", extra={
                    'order_id': str(order.id),
                    'order_number': order.order_number,
                    'order_status': order.status,
                    'user_email': order.user.email
                })
            except TransferOrder.DoesNotExist as e:
                error_msg = f"TransferOrder with ID {order_id} does not exist"
                logger.error(error_msg, exc_info=True)
                if is_ajax:
                    return JsonResponse({'error': error_msg}, status=404)
                else:
                    messages.error(request, error_msg)
                    return redirect('download-dashboard')
            except Exception as e:
                error_msg = f"Error fetching TransferOrder: {str(e)}"
                logger.error(error_msg, exc_info=True)
                if is_ajax:
                    return JsonResponse({'error': error_msg}, status=500)
                else:
                    messages.error(request, error_msg)
                    return redirect('download-dashboard')
            valid_statuses = ['payment_completed', 'storage_selected', 'download_failed', 'download_partial']
            if order.status not in valid_statuses:
                error_msg = f'Order not ready for download. Current status: {order.status}. Valid statuses: {valid_statuses}'
                logger.warning("Order status invalid for download", extra={
                    'order_id': str(order.id),
                    'current_status': order.status,
                    'valid_statuses': valid_statuses
                })
                if is_ajax:
                    return JsonResponse({'error': error_msg}, status=400)
                else:
                    messages.error(request, error_msg)
                    return redirect('download-dashboard')
            file_selections = self._get_file_selections(order, file_ids)
            if not file_selections:
                error_msg = 'No files found for download'
                logger.warning("No file selections found", extra={
                    'order_id': str(order.id),
                    'requested_file_ids': file_ids,
                    'file_selections_count': file_selections.count() if file_selections else 0
                })
                if is_ajax:
                    return JsonResponse({'error': error_msg}, status=404)
                else:
                    messages.error(request, error_msg)
                    return redirect('download-dashboard')
            logger.info(f"File selections retrieved", extra={
                'file_count': file_selections.count(),
                'file_names': [fs.file_name for fs in file_selections]
            })
            access_token = self._get_or_refresh_access_token(order)
            if not access_token:
                error_msg = 'No valid access token available for this order'
                logger.error("Access token unavailable", extra={
                    'order_id': str(order.id),
                    'cloud_source': order.cloud_source,
                    'has_refresh_token': bool(order.refresh_token),
                    'token_expiry': str(order.token_expiry) if order.token_expiry else None
                })
                if is_ajax:
                    return JsonResponse({'error': error_msg}, status=403)
                else:
                    messages.error(request, error_msg)
                    return redirect('download-dashboard')
            logger.info("Access token obtained successfully", extra={
                'token_length': len(access_token) if access_token else 0,
                'cloud_source': order.cloud_source
            })
            try:
                order.status = 'download_in_progress'
                order.download_status = f'Downloading {file_selections.count()} files...'
                order.save(update_fields=['status', 'download_status', 'updated_at'])
                logger.info("Order status updated", extra={
                    'new_status': order.status,
                    'download_status': order.download_status
                })
            except Exception as e:
                error_msg = f"Failed to update order status: {str(e)}"
                logger.error(error_msg, exc_info=True)
            logger.info("Starting file download", extra={
                'order_id': str(order.id),
                'file_count': file_selections.count(),
                'is_ajax': is_ajax
            })
            if is_ajax:
                logger.info("Starting async download for AJAX request")
                try:
                    import threading
                    thread = threading.Thread(
                        target=self._process_download_async,
                        args=(order, file_selections, access_token)
                    )
                    thread.daemon = True
                    thread.start()
                    logger.info("Async download thread started", extra={'order_id': str(order.id)})
                    response_data = {
                        'success': True,
                        'message': f'Download started for {file_selections.count()} files',
                        'order_id': order_id,
                        'file_count': file_selections.count()
                    }
                    return JsonResponse(response_data)
                except Exception as e:
                    error_msg = f"Failed to start async download thread: {str(e)}"
                    logger.error(error_msg, exc_info=True, extra={'order_id': str(order.id)})
                    return JsonResponse({'error': error_msg}, status=500)
            else:
                logger.info("Processing form submission download")
                try:
                    if file_selections.count() == 1:
                        return self._download_single_file_to_client(order, file_selections.first(), access_token)
                    else:
                        return self._download_multiple_files_as_zip(order, file_selections, access_token)
                except Exception as e:
                    error_msg = f"Failed to initiate file download: {str(e)}"
                    logger.error(error_msg, exc_info=True, extra={'order_id': str(order.id)})
        except TransferOrder.DoesNotExist:
            error_msg = f'Order not found: {order_id}'
            logger.error(error_msg, exc_info=True, extra={'order_id': order_id})
            if is_ajax:
                return JsonResponse({'error': error_msg}, status=404)
            else:
                messages.error(request, error_msg)
                return redirect('download-dashboard')
        except Exception as e:
            error_msg = f'Download failed: {str(e)}'
            logger.error(error_msg, exc_info=True, extra={
                'order_id': order_id if 'order_id' in locals() else None,
                'exception_type': type(e).__name__,
                'is_ajax': is_ajax
            })
            try:
                if 'order' in locals() and order:
                    order.status = 'download_failed'
                    order.download_status = f"Download failed: {str(e)[:100]}..."
                    order.save(update_fields=['status', 'download_status', 'updated_at'])
                    logger.info("Order status updated to failed", extra={
                        'order_id': str(order.id),
                        'error_message': str(e)[:200]
                    })
            except Exception as update_error:
                logger.error("Failed to update order status after download failure", 
                            exc_info=True, 
                            extra={'order_id': order_id if 'order_id' in locals() else None})
            if is_ajax:
                return JsonResponse({'error': error_msg}, status=500)
            else:
                messages.error(request, error_msg)
                return redirect('download-dashboard')       

    def _process_download_async(self, order, file_selections, access_token):
        try:
            if file_selections.count() == 1:
                self._download_single_file_to_client(order, file_selections.first(), access_token)
            else:
                self._download_multiple_files_as_zip(order, file_selections, access_token)
        except Exception as e:
            pass

    def _get_file_selections(self, order, file_ids):
        if file_ids:
            return order.file_selections.filter(id__in=file_ids)
        return order.file_selections.all()

    def _download_single_file_to_client(self, order, file_selection, access_token):
        from django.http import HttpResponse
        try:
            order.download_started_at = timezone.now()
            order.save(update_fields=['download_started_at'])
            file_selection.download_status = 'downloading'
            file_selection.save(update_fields=['download_status'])
            self.last_downloaded_google_filename = None
            file_content = self._get_file_content_from_cloud(
                access_token, order.cloud_source, file_selection, file_selection.file_name
            )
            if not file_content:
                raise Exception("Downloaded file content is empty")
            updated_filename = getattr(self, 'last_downloaded_google_filename', None)
            if updated_filename:
                filename_for_download = updated_filename
            else:
                filename_for_download = file_selection.file_name
            safe_filename = self._get_safe_filename(filename_for_download)
            response = HttpResponse(
                file_content,
                content_type='application/octet-stream'
            )
            response['Content-Disposition'] = f'attachment; filename="{safe_filename}"'
            response['Content-Length'] = len(file_content)
            file_selection.downloaded_filename = filename_for_download
            file_selection.download_status = 'downloaded'
            file_selection.downloaded_at = timezone.now()
            file_selection.download_size = len(file_content)
            file_selection.save(update_fields=[
                'downloaded_filename', 'download_status', 
                'downloaded_at', 'download_size'
            ])
            order.status = 'download_completed'
            order.download_completed_at = timezone.now()
            order.download_status = f'File downloaded successfully ({self._format_bytes(len(file_content))})'
            order.download_log = {
                'downloaded_files': [{
                    'name': filename_for_download,
                    'size': len(file_content),
                    'downloaded_at': timezone.now().isoformat()
                }],
                'failed_files': [],
                'total_files': 1,
                'successful_downloads': 1,
                'failed_downloads': 0,
                'total_downloaded_size': len(file_content),
                'download_duration': (timezone.now() - order.download_started_at).total_seconds(),
                'completed_at': timezone.now().isoformat()
            }
            order.save(update_fields=[
                'status', 'download_completed_at', 'download_status', 
                'download_log', 'updated_at'
            ])
            return response
        except Exception as e:
            file_selection.download_status = 'failed'
            file_selection.download_error = str(e)
            file_selection.save(update_fields=['download_status', 'download_error'])
            order.status = 'download_failed'
            order.download_status = f"Download failed: {str(e)}"
            order.save(update_fields=['status', 'download_status', 'updated_at'])
            raise
    
    def _download_multiple_files_as_zip(self, order, file_selections, access_token):
        import zipfile
        from django.http import HttpResponse
        from io import BytesIO
        try:
            total_files = file_selections.count()
            zip_buffer = BytesIO()
            with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zipf:
                downloaded_files = []
                failed_files = []
                total_downloaded_size = 0
                for index, file_selection in enumerate(file_selections, 1):
                    try:
                        file_selection.download_status = 'downloading'
                        file_selection.save(update_fields=['download_status'])
                        self.last_downloaded_google_filename = None
                        file_content = self._get_file_content_from_cloud(
                            access_token, order.cloud_source, file_selection, file_selection.file_name
                        )
                        if not file_content:
                            raise Exception("Downloaded file content is empty")
                        updated_filename = getattr(self, 'last_downloaded_google_filename', None)
                        if updated_filename:
                            filename_for_zip = updated_filename
                        else:
                            filename_for_zip = file_selection.file_name
                        safe_filename = self._get_safe_filename(filename_for_zip)
                        zipf.writestr(safe_filename, file_content)
                        file_selection.downloaded_filename = filename_for_zip
                        file_selection.download_status = 'downloaded'
                        file_selection.downloaded_at = timezone.now()
                        file_selection.download_size = len(file_content)
                        file_selection.save(update_fields=[
                            'downloaded_filename', 'download_status', 
                            'downloaded_at', 'download_size'
                        ])
                        downloaded_files.append({
                            'name': filename_for_zip,
                            'size': len(file_content)
                        })
                        total_downloaded_size += len(file_content)
                    except Exception as file_error:
                        file_selection.download_status = 'failed'
                        file_selection.download_error = str(file_error)
                        file_selection.save(update_fields=['download_status', 'download_error'])
                        failed_files.append({
                            'name': file_selection.file_name,
                            'error': str(file_error)
                        })
            zip_buffer.seek(0)
            zip_filename = f"Order_{order.order_number}_Files.zip"
            response = HttpResponse(
                zip_buffer.getvalue(),
                content_type='application/zip'
            )
            response['Content-Disposition'] = f'attachment; filename="{zip_filename}"'
            response['Content-Length'] = len(zip_buffer.getvalue())
            successful_downloads = len(downloaded_files)
            total_downloaded_size = sum(f['size'] for f in downloaded_files)
            if len(failed_files) == 0:
                order.status = 'download_completed'
                order.download_status = f'All {total_files} files downloaded successfully ({self._format_bytes(total_downloaded_size)})'
            elif successful_downloads == 0:
                order.status = 'download_failed'
                order.download_status = f'All {total_files} files failed to download'
            else:
                order.status = 'download_partial'
                order.download_status = f'{successful_downloads}/{total_files} files downloaded successfully'
            order.download_log = {
                'downloaded_files': downloaded_files,
                'failed_files': failed_files,
                'total_files': total_files,
                'successful_downloads': successful_downloads,
                'failed_downloads': len(failed_files),
                'total_downloaded_size': total_downloaded_size,
                'completed_at': timezone.now().isoformat()
            }
            order.save(update_fields=['status', 'download_status', 'download_log', 'updated_at'])
            return response
        except Exception as e:
            order.status = 'download_failed'
            order.download_status = f"Download failed: FOR THE ZIP FILE"
            order.save(update_fields=['status', 'download_status', 'updated_at'])
            raise

    def _get_file_content_from_cloud(self, access_token, cloud_source, file_selection, file_name):
        try:
            if file_selection.local_file:
                return self._download_local_file(file_selection.local_file.id)
            cloud_file_id = file_selection.file_id
            if cloud_source == 'google_drive':
                return self._download_from_google_drive(access_token, cloud_file_id, file_name)
            elif cloud_source == 'dropbox':
                return self._download_from_dropbox(access_token, cloud_file_id)
            elif cloud_source == 'onedrive':
                return self._download_from_onedrive(access_token, cloud_file_id)
            else:
                raise Exception(f"Unsupported source: {cloud_source}")
        except Exception as e:
            raise
                  
    def _download_local_file(self, file_id):
        try:
            uploaded_file = LocalUploadedFile.objects.get(id=file_id)
            if not uploaded_file.file or not os.path.exists(uploaded_file.file.path):
                raise Exception(f"Local file not found on server: {uploaded_file.original_name}")
            with open(uploaded_file.file.path, 'rb') as f:
                file_content = f.read()
            if not file_content:
                raise Exception("Local file is empty")
            return file_content
        except LocalUploadedFile.DoesNotExist:
            raise Exception(f"Local uploaded file not found: {file_id}")
        except Exception as e:
            raise Exception(f"Failed to download local file: {str(e)}")

    def download_single_local_file(request, file_id):
        try:
            uploaded_file = LocalUploadedFile.objects.get(id=file_id)
            if not uploaded_file.file or not os.path.exists(uploaded_file.file_path):
                return HttpResponse("File not found on server", status=404)
            response = FileResponse(
                open(uploaded_file.file_path, 'rb'),
                content_type='application/octet-stream'
            )
            response['Content-Disposition'] = f'attachment; filename="{uploaded_file.original_name}"'
            response['Content-Length'] = uploaded_file.file_size
            return response
        except LocalUploadedFile.DoesNotExist:
            return HttpResponse("File not found", status=404)
        except Exception as e:
            return HttpResponse(f"Error: {str(e)}", status=500)

    @action(detail=False, methods=['get'], url_path=r'download-local/(?P<file_id>[^/.]+)')
    def download_local_file(self, request, file_id=None):
            if not request.user.is_staff:
                return JsonResponse({'error': 'Admin access required'}, status=403)
            try:
                uploaded_file = LocalUploadedFile.objects.get(id=file_id)
                if not uploaded_file.file or not os.path.exists(uploaded_file.file.path):
                    return HttpResponse("File not found on server", status=404)
                response = FileResponse(
                    open(uploaded_file.file.path, 'rb'),
                    content_type='application/octet-stream'
                )
                response['Content-Disposition'] = f'attachment; filename="{uploaded_file.original_name}"'
                response['Content-Length'] = uploaded_file.file_size
                return response
            except LocalUploadedFile.DoesNotExist:
                return HttpResponse("File not found", status=404)
            except Exception as e:
                logger.error(f"Error downloading local file {file_id}: {str(e)}")
                return HttpResponse(f"Error: {str(e)}", status=500)
    
    def _update_order_status(self, order, downloaded_files, failed_files, total_files):
        successful_downloads = len(downloaded_files)
        total_downloaded_size = sum(f['size'] for f in downloaded_files)
        if len(failed_files) == 0:
            order.status = 'download_completed'
            order.download_status = f'All {total_files} files downloaded successfully ({self._format_bytes(total_downloaded_size)})'
        elif successful_downloads == 0:
            order.status = 'download_failed'
            order.download_status = f'All {total_files} files failed to download'
        else:
            order.status = 'download_partial'
            order.download_status = f'{successful_downloads}/{total_files} files downloaded successfully'
        order.download_log = {
            'downloaded_files': downloaded_files,
            'failed_files': failed_files,
            'total_files': total_files,
            'successful_downloads': successful_downloads,
            'failed_downloads': len(failed_files),
            'total_downloaded_size': total_downloaded_size,
            'completed_at': timezone.now().isoformat()
        }
        order.save(update_fields=['status', 'download_status', 'download_log', 'updated_at'])

    def _download_from_dropbox(self, access_token, file_id):
        try:
            headers = {
                'Authorization': f'Bearer {access_token}',
                'Dropbox-API-Arg': f'{{"path": "{file_id}"}}'
            }
            response = requests.post(
                'https://content.dropboxapi.com/2/files/download',
                headers=headers,
                stream=True,
                timeout=60
            )
            response.raise_for_status()
            content = b''
            for chunk in response.iter_content(chunk_size=8192):
                if chunk:
                    content += chunk
            return content
        except requests.exceptions.RequestException as e:
            raise Exception(f"Dropbox download failed: {str(e)}")

    def _download_from_onedrive(self, access_token, file_id):
        try:
            headers = {'Authorization': f'Bearer {access_token}'}
            download_url = f'https://graph.microsoft.com/v1.0/me/drive/items/{file_id}/content'
            response = requests.get(download_url, headers=headers, stream=True, timeout=60)
            response.raise_for_status()
            content = b''
            for chunk in response.iter_content(chunk_size=8192):
                if chunk:
                    content += chunk
            return content
        except requests.exceptions.RequestException as e:
            raise Exception(f"OneDrive download failed: {str(e)}")

    def _get_safe_filename(self, filename):
        import re
        import os
        name, ext = os.path.splitext(filename)
        safe_name = re.sub(r'[<>:"/\\|?*]', '_', name)
        safe_name = safe_name[:200]
        return safe_name + ext

    def _format_bytes(self, size_bytes):
        for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
            if size_bytes < 1024.0:
                return f"{size_bytes:.2f} {unit}"
            size_bytes /= 1024.0
        return f"{size_bytes:.2f} PB"

    @action(detail=False, methods=['get'], url_path=r'')
    def get_order_files(self, request, order_id=None):
        try:
            from ..models import TransferOrder
            order = TransferOrder.objects.get(id=order_id)
            file_selections = order.file_selections.all().order_by('file_name')
            files_data = []
            for file_selection in file_selections:
                files_data.append({
                    'id': str(file_selection.id),
                    'name': file_selection.file_name,
                    'size': file_selection.file_size,
                    'download_status': file_selection.download_status,
                    'download_error': file_selection.download_error,
                    'downloaded_at': file_selection.downloaded_at.isoformat() if file_selection.downloaded_at else None,
                    'download_size': file_selection.download_size,
                    'selected': False
                })
            return JsonResponse({
                'order_id': str(order.id),
                'order_number': order.order_number,
                'user_email': order.user.email,
                'cloud_source': order.cloud_source,
                'total_files': len(files_data),
                'files': files_data
            })
        except TransferOrder.DoesNotExist:
            return JsonResponse({'error': 'Order not found'}, status=404)
        except Exception as e:
            return JsonResponse({'error': f'Failed to get order files: {str(e)}'}, status=500)

    def _get_or_refresh_access_token(self, order):
        from social_django.models import UserSocialAuth
        if order.access_token and order.token_expiry and order.token_expiry > timezone.now():
            return order.access_token
        if order.refresh_token:
            new_token = self._refresh_oauth_token(order)
            if new_token:
                return new_token
        try:
            social_auth = UserSocialAuth.objects.filter(
                user=order.user, 
                provider='google-oauth2'
            ).first()
            if social_auth and social_auth.extra_data.get('access_token'):
                order.access_token = social_auth.extra_data.get('access_token')
                order.refresh_token = social_auth.extra_data.get('refresh_token')
                order.token_expiry = timezone.now() + timezone.timedelta(hours=1)
                order.save(update_fields=['access_token', 'refresh_token', 'token_expiry'])
                return order.access_token
        except Exception as e:
            pass
        return None

    def _refresh_oauth_token(self, order):
        from django.conf import settings
        if order.cloud_source == 'google_drive' and order.refresh_token:
            try:
                response = requests.post('https://oauth2.googleapis.com/token', data={
                    'client_id': settings.SOCIAL_AUTH_GOOGLE_OAUTH2_KEY,
                    'client_secret': settings.SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET,
                    'refresh_token': order.refresh_token,
                    'grant_type': 'refresh_token'
                }, timeout=30)
                if response.status_code == 200:
                    token_data = response.json()
                    new_access_token = token_data.get('access_token')
                    if not new_access_token:
                        raise Exception("No access token received in refresh response")
                    order.access_token = new_access_token
                    order.token_expiry = timezone.now() + timezone.timedelta(
                        seconds=token_data.get('expires_in', 3600)
                    )
                    order.save(update_fields=['access_token', 'token_expiry'])
                    return new_access_token
                else:
                    error_msg = f"Token refresh failed with status {response.status_code}"
                    raise Exception(error_msg)
            except requests.exceptions.Timeout:
                error_msg = "Token refresh request timed out"
                raise Exception(error_msg)
            except Exception as e:
                error_msg = f"Token refresh failed: {str(e)}"
                raise Exception(error_msg)
        return None  
    
    @action(detail=False, methods=['get'], url_path=r'direct-download/(?P<order_id>[^/.]+)')
    def direct_download(self, request, order_id=None):
        try:
            from ..models import TransferOrder
            order = TransferOrder.objects.get(id=order_id)
            file_selections = order.file_selections.all()
            access_token = self._get_or_refresh_access_token(order)
            if not access_token:
                messages.error(request, "No valid access token")
                return redirect('download-dashboard')
            order.status = 'download_in_progress'
            order.download_status = f'Downloading {file_selections.count()} files...'
            order.save(update_fields=['status', 'download_status', 'updated_at'])
            if file_selections.count() == 1:
                return self._download_single_file_to_client(order, file_selections.first(), access_token)
            else:
                return self._download_multiple_files_as_zip(order, file_selections, access_token)
        except Exception as e:
            messages.error(request, f"Download failed: {str(e)}")
            return redirect('download-dashboard')
         
    @action(detail=False, methods=['get'], url_path=r'')
    def get_download_status(self, request, order_id=None):
        try:
            from ..models import TransferOrder
            order = TransferOrder.objects.get(id=order_id)
            total_files = order.file_selections.count()
            downloaded_files = order.file_selections.filter(download_status='downloaded').count()
            overall_progress = 0
            if total_files > 0:
                overall_progress = int((downloaded_files / total_files) * 100)
            file_progress = []
            for file_selection in order.file_selections.all():
                file_progress.append({
                    'id': str(file_selection.id),
                    'name': file_selection.file_name,
                    'status': file_selection.download_status,
                    'progress': getattr(file_selection, 'progress_percentage', 0),
                    'size': file_selection.download_size or file_selection.file_size,
                    'error': file_selection.download_error
                })
            return JsonResponse({
                'order_id': str(order.id),
                'order_number': order.order_number,
                'status': order.status,
                'progress': overall_progress,
                'total_files': total_files,
                'downloaded_files': downloaded_files,
                'files': file_progress,
                'download_status': order.download_status,
                'user_email': order.user.email,
                'started_at': order.download_started_at.isoformat() if order.download_started_at else None,
                'download_log': order.download_log or {}
            })
        except TransferOrder.DoesNotExist:
            return JsonResponse({'error': 'Order not found'}, status=404)
        except Exception as e:
            return JsonResponse({'error': f'Failed to get status: {str(e)}'}, status=500)
    
    def _download_from_google_drive(self, access_token, file_id, file_name, file_selection=None):
        try:
            from googleapiclient.discovery import build
            from googleapiclient.http import MediaIoBaseDownload
            from google.auth.transport.requests import Request
            from google.oauth2.credentials import Credentials
            from googleapiclient.errors import HttpError
            import io
            import os
            creds = Credentials(token=access_token)
            service = build('drive', 'v3', credentials=creds)
            file_metadata = service.files().get(
                fileId=file_id, 
                fields='mimeType,name,size,webViewLink'
            ).execute()
            mime_type = file_metadata.get('mimeType', '')
            original_name = file_metadata.get('name', file_name)
            updated_filename = original_name
            google_workspace_mappings = {
                'application/vnd.google-apps.document': {
                    'export_mime': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
                    'export_extension': '.docx',
                    'google_extension': '.gdoc'
                },
                'application/vnd.google-apps.spreadsheet': {
                    'export_mime': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                    'export_extension': '.xlsx',
                    'google_extension': '.gsheet'
                },
                'application/vnd.google-apps.presentation': {
                    'export_mime': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
                    'export_extension': '.pptx',
                    'google_extension': '.gslides'
                },
                'application/vnd.google-apps.drawing': {
                    'export_mime': 'image/png',
                    'export_extension': '.png',
                    'google_extension': '.gdraw'
                },
                'application/vnd.google-apps.form': {
                    'export_mime': 'application/pdf',
                    'export_extension': '.pdf',
                    'google_extension': '.gform'
                },
                'application/vnd.google-apps.jam': {
                    'export_mime': 'application/pdf',
                    'export_extension': '.pdf',
                    'google_extension': '.jam'
                },
                'application/vnd.google-apps.map': {
                    'export_mime': 'application/vnd.google-earth.kml+xml',
                    'export_extension': '.kml',
                    'google_extension': '.gmap'
                }
            }
            if mime_type.startswith('application/vnd.google-apps'):
                mapping = google_workspace_mappings.get(mime_type)
                if not mapping:
                    mapping = {
                        'export_mime': 'application/pdf',
                        'export_extension': '.pdf',
                        'google_extension': ''
                    }
                download_mime_type = mapping['export_mime']
                new_extension = mapping['export_extension']
                google_extension = mapping.get('google_extension', '')
                request = service.files().export_media(
                    fileId=file_id, 
                    mimeType=download_mime_type
                )
                original_base_name = os.path.splitext(original_name)[0]
                if google_extension and original_name.endswith(google_extension):
                    original_base_name = original_name[:-len(google_extension)]
                else:
                    google_extensions = ['.gdoc', '.gsheet', '.gslides', '.gdraw', '.gform', '.gmap', '.jam']
                    for ext in google_extensions:
                        if original_name.endswith(ext):
                            original_base_name = original_name[:-len(ext)]
                            break
                updated_filename = f"{original_base_name}{new_extension}"
                if file_selection:
                    file_selection.downloaded_filename = updated_filename
                    try:
                        file_selection.save(update_fields=['downloaded_filename'])
                    except:
                        pass
            else:
                request = service.files().get_media(fileId=file_id)
            fh = io.BytesIO()
            downloader = MediaIoBaseDownload(fh, request)
            done = False
            while not done:
                status, done = downloader.next_chunk()
                if status:
                    progress_percentage = int(status.progress() * 100)
                    if file_selection:
                        try:
                            from django.db import transaction
                            with transaction.atomic():
                                file_selection.progress_percentage = progress_percentage
                                file_selection.download_status = 'downloading'
                                if mime_type.startswith('application/vnd.google-apps'):
                                    file_selection.downloaded_filename = updated_filename
                                file_selection.save(update_fields=['progress_percentage', 'download_status', 'downloaded_filename'])
                        except Exception as e:
                            pass
            fh.seek(0)
            file_content = fh.getvalue()
            fh.close()
            if not file_content:
                raise Exception("Downloaded file content is empty")
            self.last_downloaded_google_filename = updated_filename
            return file_content
        except HttpError as error:
            if error.resp.status == 403:
                raise Exception("Permission denied: Check file sharing and app scopes")
            elif error.resp.status == 404:
                raise Exception("File not found or inaccessible")
            elif error.resp.status == 401:
                raise Exception("Authentication failed: Token expired or invalid")
            else:
                raise Exception(f"Google Drive API error: {error}")
        except Exception as e:
            raise

    @action(detail=False, methods=['get'], url_path=r'')
    def get_file_download_status(self, request, order_id=None, file_id=None):
        try:
            from ..models import FileSelection
            file_selection = FileSelection.objects.get(id=file_id, order_id=order_id)
            return JsonResponse({
                'file_id': str(file_selection.id),
                'name': file_selection.file_name,
                'status': file_selection.download_status,
                'progress': file_selection.progress_percentage if hasattr(file_selection, 'progress_percentage') else 0,
                'size': file_selection.file_size,
                'downloaded_size': file_selection.download_size or 0,
                'error': file_selection.download_error,
                'started_at': file_selection.downloaded_at.isoformat() if file_selection.download_status == 'downloading' else None,
                'completed_at': file_selection.downloaded_at.isoformat() if file_selection.download_status == 'downloaded' else None
            })
        except FileSelection.DoesNotExist:
            return JsonResponse({'error': 'File not found'}, status=404)
        except Exception as e:
            return JsonResponse({'error': f'Failed to get file status: {str(e)}'}, status=500)

    @action(detail=False, methods=['post'], url_path=r'retry-failed-files/(?P<order_id>[^/.]+)')
    def retry_failed_files(self, request, order_id=None):
        try:
            from ..models import TransferOrder, FileSelection
            order = TransferOrder.objects.get(id=order_id)
            failed_files = order.file_selections.filter(download_status='failed')
            if not failed_files.exists():
                return JsonResponse({'error': 'No failed files to retry'}, status=400)
            failed_files.update(
                download_status='pending',
                download_error=None,
            )
            order.status = 'download_in_progress'
            order.download_status = f'Retrying {failed_files.count()} failed files...'
            order.save(update_fields=['status', 'download_status', 'updated_at'])
            return JsonResponse({
                'success': True,
                'message': f'Retrying {failed_files.count()} failed files',
                'order_id': str(order.id),
                'retry_count': failed_files.count()
            })
        except TransferOrder.DoesNotExist:
            return JsonResponse({'error': 'Order not found'}, status=404)
        except Exception as e:
            return JsonResponse({'error': f'Failed to retry files: {str(e)}'}, status=500)