# apps/artworks/tasks.py - TÂCHES CELERY ASYNCHRONES

from celery import shared_task
from django.core.files import File
from django.utils import timezone
from django.db.models import Count, Avg
from datetime import timedelta
from gtts import gTTS
import tempfile
import os

from .models import (
    Artwork, ArtworkTranslation, AudioGuide, Statistics, Visit, Media
)


# ==================== GÉNÉRATION AUDIO ====================
@shared_task(bind=True, max_retries=3)
def generate_audio_guide(self, translation_id):
    """Génère un guide audio pour une traduction d'œuvre"""
    try:
        translation = ArtworkTranslation.objects.get(id=translation_id)

        # Vérifier si l'audio existe déjà
        if AudioGuide.objects.filter(artwork_translation=translation).exists():
            return {'status': 'exists', 'translation_id': str(translation_id)}

        # Générer l'audio avec gTTS
        text = f"{translation.title}. {translation.description}"

        # Langue pour gTTS (Wolof pas supporté, utiliser français)
        gtts_lang = translation.language if translation.language in ['fr', 'en'] else 'fr'

        tts = gTTS(text=text, lang=gtts_lang, slow=False)

        # Sauvegarder dans un fichier temporaire
        with tempfile.NamedTemporaryFile(delete=False, suffix='.mp3') as temp_file:
            tts.save(temp_file.name)
            temp_file.seek(0)

            # Calculer la durée approximative (250 mots par minute)
            word_count = len(text.split())
            duration = int((word_count / 250) * 60)

            # Créer l'AudioGuide
            audio_guide = AudioGuide.objects.create(
                artwork_translation=translation,
                duration=duration,
                narrator='Système TTS'
            )

            # Sauvegarder le fichier audio
            filename = f"{translation.artwork.reference_code}_{translation.language}.mp3"
            with open(temp_file.name, 'rb') as f:
                audio_guide.audio_file.save(filename, File(f))

            # Nettoyer le fichier temporaire
            os.unlink(temp_file.name)

        return {'status': 'success', 'audio_guide_id': str(audio_guide.id)}

    except ArtworkTranslation.DoesNotExist:
        return {'status': 'error', 'message': 'Traduction introuvable'}
    except Exception as exc:
        # Réessayer jusqu'à 3 fois
        raise self.retry(exc=exc, countdown=60)


@shared_task
def generate_all_audio_guides():
    """Génère tous les guides audio manquants"""
    translations = ArtworkTranslation.objects.filter(
        artwork__is_published=True
    ).exclude(
        audio_guides__isnull=False
    )

    count = 0
    for translation in translations:
        generate_audio_guide.delay(str(translation.id))
        count += 1

    return {'status': 'scheduled', 'count': count}


# ==================== TRAITEMENT MÉDIA ====================
@shared_task(bind=True, max_retries=3)
def process_media_file(self, media_id):
    """Traite un fichier média (génération de miniatures, etc.)"""
    try:
        from PIL import Image
        import io

        media = Media.objects.get(id=media_id)

        if media.media_type == 'image' and not media.thumbnail:
            # Générer une miniature
            img = Image.open(media.file)

            # Redimensionner
            img.thumbnail((300, 300), Image.Resampling.LANCZOS)

            # Sauvegarder dans un buffer
            buffer = io.BytesIO()
            img.save(buffer, format='JPEG', quality=85)
            buffer.seek(0)

            # Sauvegarder la miniature
            filename = f"thumb_{os.path.basename(media.file.name)}"
            media.thumbnail.save(filename, File(buffer), save=True)

            return {'status': 'success', 'media_id': str(media_id)}

        return {'status': 'skipped', 'media_id': str(media_id)}

    except Media.DoesNotExist:
        return {'status': 'error', 'message': 'Média introuvable'}
    except Exception as exc:
        raise self.retry(exc=exc, countdown=60)


# ==================== STATISTIQUES QUOTIDIENNES ====================
@shared_task
def generate_daily_statistics():
    """Génère les statistiques quotidiennes (CRON: tous les jours à 02:00)"""
    today = timezone.now().date()
    yesterday = today - timedelta(days=1)

    # Vérifier si les stats existent déjà
    if Statistics.objects.filter(date=yesterday).exists():
        return {'status': 'exists', 'date': str(yesterday)}

    # Calcul des statistiques
    visits_yesterday = Visit.objects.filter(visited_at__date=yesterday)

    total_visits = visits_yesterday.count()
    unique_visitors = visits_yesterday.values('ip_address').distinct().count()
    qr_scans = visits_yesterday.filter(source='qr').count()

    # Œuvre la plus vue
    most_viewed = Artwork.objects.filter(
        visits__visited_at__date=yesterday
    ).annotate(
        visits_count=Count('visits')
    ).order_by('-visits_count').first()

    # Temps moyen par œuvre (simulation - à implémenter avec tracking réel)
    avg_time = 180.0  # 3 minutes par défaut

    # Créer les statistiques
    stats = Statistics.objects.create(
        date=yesterday,
        total_visits=total_visits,
        unique_visitors=unique_visitors,
        qr_scans=qr_scans,
        most_viewed_artwork=most_viewed,
        avg_time_per_artwork=avg_time
    )

    return {
        'status': 'success',
        'stats_id': str(stats.id),
        'date': str(yesterday),
        'total_visits': total_visits
    }


@shared_task
def send_daily_report():
    """Envoie le rapport quotidien par email aux admins"""
    from django.core.mail import send_mail
    from django.contrib.auth import get_user_model

    User = get_user_model()
    today = timezone.now().date()
    yesterday = today - timedelta(days=1)

    try:
        stats = Statistics.objects.get(date=yesterday)

        # Récupérer les admins
        admins = User.objects.filter(role='museum_admin', is_active=True)
        admin_emails = [admin.email for admin in admins if admin.email]

        if not admin_emails:
            return {'status': 'no_recipients'}

        # Composer le message
        subject = f'Rapport quotidien MCN - {yesterday.strftime("%d/%m/%Y")}'
        message = f"""
Bonjour,

Voici le rapport quotidien du Musée des Civilisations Noires pour le {yesterday.strftime("%d/%m/%Y")}:

📊 STATISTIQUES:
- Visites totales: {stats.total_visits}
- Visiteurs uniques: {stats.unique_visitors}
- Scans QR Code: {stats.qr_scans}
- Temps moyen/œuvre: {stats.avg_time_per_artwork:.1f} secondes

🎨 ŒUVRE LA PLUS VUE:
{stats.most_viewed_artwork.reference_code if stats.most_viewed_artwork else 'N/A'}

Cordialement,
Système MCN Museum
"""

        send_mail(
            subject,
            message,
            'noreply@mcn-museum.sn',
            admin_emails,
            fail_silently=False,
        )

        return {'status': 'sent', 'recipients': len(admin_emails)}

    except Statistics.DoesNotExist:
        return {'status': 'no_stats'}
    except Exception as e:
        return {'status': 'error', 'message': str(e)}


# ==================== NETTOYAGE ====================
@shared_task
def cleanup_old_visits():
    """Nettoie les anciennes visites (plus de 6 mois)"""
    six_months_ago = timezone.now() - timedelta(days=180)
    deleted_count, _ = Visit.objects.filter(visited_at__lt=six_months_ago).delete()

    return {'status': 'success', 'deleted': deleted_count}


@shared_task
def cleanup_orphan_media():
    """Nettoie les médias orphelins (sans œuvre associée)"""
    orphan_media = Media.objects.filter(artwork__isnull=True)
    count = orphan_media.count()

    # Supprimer les fichiers
    for media in orphan_media:
        if media.file:
            media.file.delete()
        if media.thumbnail:
            media.thumbnail.delete()

    # Supprimer les enregistrements
    orphan_media.delete()

    return {'status': 'success', 'deleted': count}


# ==================== CACHE MANAGEMENT ====================
@shared_task
def invalidate_artwork_cache(artwork_id):
    """Invalide le cache d'une œuvre spécifique"""
    from django.core.cache import cache

    # Invalider pour toutes les langues
    for lang in ['fr', 'en', 'wo']:
        cache_key = f'artwork_{artwork_id}_{lang}'
        cache.delete(cache_key)

    return {'status': 'success', 'artwork_id': str(artwork_id)}


@shared_task
def warm_cache():
    """Précharge le cache avec les œuvres populaires"""
    from django.core.cache import cache
    from .serializers import ArtworkDetailSerializer

    # Récupérer les 20 œuvres les plus vues
    popular_artworks = Artwork.objects.filter(
        is_published=True
    ).order_by('-view_count')[:20]

    count = 0
    for artwork in popular_artworks:
        for lang in ['fr', 'en', 'wo']:
            cache_key = f'artwork_{artwork.id}_{lang}'
            serializer = ArtworkDetailSerializer(artwork)
            cache.set(cache_key, serializer.data, 3600)  # 1 heure
            count += 1

    return {'status': 'success', 'cached': count}


# ==================== GÉNÉRATION QR CODES EN MASSE ====================
@shared_task
def generate_all_qr_codes():
    """Génère les QR codes manquants pour toutes les œuvres"""
    artworks = Artwork.objects.filter(qr_code='')

    count = 0
    for artwork in artworks:
        try:
            artwork.generate_qr_code()
            artwork.save(update_fields=['qr_code'])
            count += 1
        except Exception as e:
            print(f"Erreur QR code pour {artwork.reference_code}: {e}")

    return {'status': 'success', 'generated': count}


# ==================== EXPORT DATA ====================
@shared_task
def export_artworks_to_json():
    """Exporte toutes les œuvres en JSON pour backup"""
    import json
    from django.core.serializers import serialize

    artworks = Artwork.objects.filter(is_published=True)
    data = serialize('json', artworks)

    # Sauvegarder dans un fichier
    filename = f"artworks_export_{timezone.now().strftime('%Y%m%d_%H%M%S')}.json"
    filepath = f'/tmp/{filename}'

    with open(filepath, 'w', encoding='utf-8') as f:
        f.write(data)

    return {'status': 'success', 'file': filepath, 'count': artworks.count()}

