import datetime
import logging
import tempfile

from django.conf import settings
from django.core.files import File
from django.db import transaction
from django.dispatch import receiver
from django.utils import timezone

from funkwhale_api.common import channels
from funkwhale_api.taskapp import celery

from . import models, serializers, session, signals

logger = logging.getLogger(__name__)


@celery.app.task(name="common.apply_mutation")
@transaction.atomic
@celery.require_instance(
    models.Mutation.objects.exclude(is_applied=True).select_for_update(), "mutation"
)
def apply_mutation(mutation):
    mutation.apply()


@receiver(signals.mutation_created)
def broadcast_mutation_created(mutation, **kwargs):
    group = "instance_activity"
    channels.group_send(
        group,
        {
            "type": "event.send",
            "text": "",
            "data": {
                "type": "mutation.created",
                "mutation": serializers.APIMutationSerializer(mutation).data,
                "pending_review_count": models.Mutation.objects.filter(
                    is_approved=None
                ).count(),
            },
        },
    )


@receiver(signals.mutation_updated)
def broadcast_mutation_update(mutation, old_is_approved, new_is_approved, **kwargs):
    group = "instance_activity"
    channels.group_send(
        group,
        {
            "type": "event.send",
            "text": "",
            "data": {
                "type": "mutation.updated",
                "mutation": serializers.APIMutationSerializer(mutation).data,
                "pending_review_count": models.Mutation.objects.filter(
                    is_approved=None
                ).count(),
                "old_is_approved": old_is_approved,
                "new_is_approved": new_is_approved,
            },
        },
    )


def fetch_remote_attachment(attachment, filename=None, save=True):
    if attachment.file:
        # already there, no need to fetch
        return

    s = session.get_session()
    attachment.last_fetch_date = timezone.now()
    with tempfile.TemporaryFile() as tf:
        with s.get(attachment.url, timeout=5, stream=True) as r:
            for chunk in r.iter_content(chunk_size=1024 * 100):
                tf.write(chunk)
            tf.seek(0)
            if not filename:
                filename = attachment.url.split("/")[-1]
                filename = filename[-50:]
            attachment.file.save(filename, File(tf), save=save)


@celery.app.task(name="common.prune_unattached_attachments")
def prune_unattached_attachments():
    limit = timezone.now() - datetime.timedelta(
        seconds=settings.ATTACHMENTS_UNATTACHED_PRUNE_DELAY
    )
    candidates = models.Attachment.objects.attached(False).filter(
        creation_date__lte=limit
    )

    total = candidates.count()
    logger.info("Deleting %s unattached attachments…", total)
    result = candidates.delete()
    logger.info("Deletion done: %s", result)
