
import base64
import logging
import traceback
from typing import Dict, Any

from core.celery_app import celery_app
from core.database import CoreSessionLocal
from core.email import EmailService
from datetime import datetime

from .movement_service import movement_service
from .schemas import AllMovementsFilter
from .csv_utils import generate_csv_from_movements

logger = logging.getLogger(__name__)

@celery_app.task(bind=True, name="generate_invoice_movements_async")
def generate_invoice_movements_async(self, filter_data: Dict[str, Any], user_email: str = None):
    """
    Async task to generate invoice movements report.
    FETCHES data -> GENERATES CSV -> SENDS EMAIL (optional) -> RETURNS CSV (base64)
    """
    db = CoreSessionLocal()
    try:
        # 1. Update Progress
        self.update_state(state='PROCESSING', meta={'current': 10, 'total': 100, 'status': 'Inicializando reporte...'})
        
        # 2. Reconstruct Filter
        filters = AllMovementsFilter(**filter_data)
        
        # 3. Fetch Data
        self.update_state(state='PROCESSING', meta={'current': 30, 'total': 100, 'status': 'Obteniendo movimientos de base de datos...'})
        logger.info(f"Async Task: Fetching movements for {filters}")
        
        movements = movement_service.get_all_movements(db=db, filters=filters)
        
        self.update_state(state='PROCESSING', meta={'current': 70, 'total': 100, 'status': f'Procesando {len(movements)} registros...'})
        
        # 4. Generate CSV
        csv_content = generate_csv_from_movements(
            movements=movements,
            filters=filters
        )
        
        # 5. Send Email if requested
        email_sent = False
        if filters.send_email and user_email:
            self.update_state(state='PROCESSING', meta={'current': 90, 'total': 100, 'status': 'Enviando correo electrónico...'})
            try:
                # Generate filename
                filename = f"reporte_facturas_{filters.start_date}_{filters.end_date}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
                
                # Send email (using the new async wrapper or run_until_complete if needed, 
                # but since we are in a sync celery task we might need to be careful with async/await.
                # Actually EmailService.send_report_email is async. 
                # We need to run it synchronously here or make the task async.
                # Celery tasks are sync by default. We can use asgiref.sync.async_to_sync
                
                import asyncio
                from asgiref.sync import async_to_sync
                
                # Helper to run async method
                result = async_to_sync(EmailService.send_report_email)(
                    recipient_email=user_email,
                    subject=f"Reporte de Facturas - {filters.start_date} al {filters.end_date}",
                    body_text=f"Se ha generado el reporte de facturas solicitado con {len(movements)} registros.",
                    csv_content=csv_content,
                    filename=filename
                )
                
                if result:
                    email_sent = True
                    logger.info(f"Async Task: Email sent to {user_email}")
                else:
                    logger.warning(f"Async Task: Failed to send email to {user_email}")
                    
            except Exception as e:
                logger.error(f"Async Task: Email error: {str(e)}")
        
        # 6. Encode and Return
        self.update_state(state='PROCESSING', meta={'current': 95, 'total': 100, 'status': 'Finalizando...'})
        
        # Convert string csv to bytes then base64
        pdf_b64 = base64.b64encode(csv_content.encode('utf-8')).decode('utf-8')
        
        return {
            'status': 'success',
            'file_name': f"reporte_facturas_{datetime.now().strftime('%Y%m%d')}.csv",
            'content': pdf_b64,
            'media_type': 'text/csv',
            'email_sent': email_sent,
            'total_records': len(movements)
        }

    except Exception as e:
        logger.error(f"Error in generate_invoice_movements_async: {str(e)}", exc_info=True)
        self.update_state(
            state='FAILURE',
            meta={
                'exc_type': type(e).__name__,
                'exc_message': str(e),
                'custom': 'Error generating report'
            }
        )
        raise e
    finally:
        db.close()
