import logging

from django.conf import settings
from django.core import mail
from django.db import transaction
from django.dispatch import receiver

from funkwhale_api.common import channels, preferences, utils
from funkwhale_api.federation import utils as federation_utils
from funkwhale_api.taskapp import celery
from funkwhale_api.users import models as users_models

from . import models, signals

logger = logging.getLogger(__name__)


@receiver(signals.report_created)
def broadcast_report_created(report, **kwargs):
    from . import serializers

    channels.group_send(
        "admin.moderation",
        {
            "type": "event.send",
            "text": "",
            "data": {
                "type": "report.created",
                "report": serializers.ReportSerializer(report).data,
                "unresolved_count": models.Report.objects.filter(
                    is_handled=False
                ).count(),
            },
        },
    )


@receiver(signals.report_created)
def trigger_moderator_email(report, **kwargs):
    if settings.MODERATION_EMAIL_NOTIFICATIONS_ENABLED:
        utils.on_commit(send_new_report_email_to_moderators.delay, report_id=report.pk)


def get_moderators():
    moderators = users_models.User.objects.filter(
        is_active=True, permission_moderation=True
    )
    if not moderators:
        # we fallback on superusers
        moderators = users_models.User.objects.filter(is_superuser=True)
    moderators = sorted(moderators, key=lambda m: m.pk)
    return moderators


@celery.app.task(name="moderation.send_new_report_email_to_moderators")
@celery.require_instance(
    models.Report.objects.select_related("submitter").filter(is_handled=False), "report"
)
def send_new_report_email_to_moderators(report):
    moderators = get_moderators()
    submitter_repr = (
        report.submitter.full_username if report.submitter else report.submitter_email
    )
    subject = "[{} moderation - {}] New report from {}".format(
        settings.FUNKWHALE_HOSTNAME, report.get_type_display(), submitter_repr
    )
    detail_url = federation_utils.full_url(f"/manage/moderation/reports/{report.uuid}")
    unresolved_reports_url = federation_utils.full_url(
        "/manage/moderation/reports?q=resolved:no"
    )
    unresolved_reports = models.Report.objects.filter(is_handled=False).count()
    body = [
        '{} just submitted a report in the "{}" category.'.format(
            submitter_repr, report.get_type_display()
        ),
        "",
        "Reported object: {} - {}".format(
            report.target._meta.verbose_name.title(), str(report.target)
        ),
    ]
    if hasattr(report.target, "get_absolute_url"):
        body.append(
            "Open public page: {}".format(
                federation_utils.full_url(report.target.get_absolute_url())
            )
        )
    if hasattr(report.target, "get_moderation_url"):
        body.append(
            "Open moderation page: {}".format(
                federation_utils.full_url(report.target.get_moderation_url())
            )
        )
    if report.summary:
        body += ["", "Report content:", "", report.summary]

    body += [
        "",
        f"- To handle this report, please visit {detail_url}",
        "- To view all unresolved reports (currently {}), please visit {}".format(
            unresolved_reports, unresolved_reports_url
        ),
        "",
        "—",
        "",
        "You are receiving this e-mail because you are a moderator for {}.".format(
            settings.FUNKWHALE_HOSTNAME
        ),
    ]

    for moderator in moderators:
        if not moderator.email:
            logger.warning(
                "Moderator %s has no e-mail address configured", moderator.username
            )
            continue
        mail.send_mail(
            subject,
            message="\n".join(body),
            recipient_list=[moderator.email],
            from_email=settings.DEFAULT_FROM_EMAIL,
        )


@celery.app.task(name="moderation.user_request_handle")
@celery.require_instance(
    models.UserRequest.objects.select_related("submitter"), "user_request"
)
@transaction.atomic
def user_request_handle(user_request, new_status, old_status=None):
    if user_request.status != new_status:
        logger.warn(
            "User request %s was handled before asynchronous tasks run", user_request.pk
        )
        return

    if user_request.type == "signup" and new_status == "pending" and old_status is None:
        notify_mods_signup_request_pending(user_request)
        broadcast_user_request_created(user_request)
    elif user_request.type == "signup" and new_status == "approved":
        user_request.submitter.user.is_active = True
        user_request.submitter.user.save(update_fields=["is_active"])
        notify_submitter_signup_request_approved(user_request)
    elif user_request.type == "signup" and new_status == "refused":
        notify_submitter_signup_request_refused(user_request)


def broadcast_user_request_created(user_request):
    from funkwhale_api.manage import serializers as manage_serializers

    channels.group_send(
        "admin.moderation",
        {
            "type": "event.send",
            "text": "",
            "data": {
                "type": "user_request.created",
                "user_request": manage_serializers.ManageUserRequestSerializer(
                    user_request
                ).data,
                "pending_count": models.UserRequest.objects.filter(
                    status="pending"
                ).count(),
            },
        },
    )


def notify_mods_signup_request_pending(obj):
    moderators = get_moderators()
    submitter_repr = obj.submitter.preferred_username
    subject = "[{} moderation] New sign-up request from {}".format(
        settings.FUNKWHALE_HOSTNAME, submitter_repr
    )
    detail_url = federation_utils.full_url(f"/manage/moderation/requests/{obj.uuid}")
    unresolved_requests_url = federation_utils.full_url(
        "/manage/moderation/requests?q=status:pending"
    )
    unresolved_requests = models.UserRequest.objects.filter(status="pending").count()
    body = [
        "{} wants to register on your pod. You need to review their request before they can use the service.".format(
            submitter_repr
        ),
        "",
        f"- To handle this request, please visit {detail_url}",
        "- To view all unresolved requests (currently {}), please visit {}".format(
            unresolved_requests, unresolved_requests_url
        ),
        "",
        "—",
        "",
        "You are receiving this e-mail because you are a moderator for {}.".format(
            settings.FUNKWHALE_HOSTNAME
        ),
    ]

    for moderator in moderators:
        if not moderator.email:
            logger.warning(
                "Moderator %s has no e-mail address configured", moderator.username
            )
            continue
        mail.send_mail(
            subject,
            message="\n".join(body),
            recipient_list=[moderator.email],
            from_email=settings.DEFAULT_FROM_EMAIL,
        )


def notify_submitter_signup_request_approved(user_request):
    submitter_repr = user_request.submitter.preferred_username
    submitter_email = user_request.submitter.user.email
    if not submitter_email:
        logger.warning("User %s has no e-mail address configured", submitter_repr)
        return
    subject = f"Welcome to {settings.FUNKWHALE_HOSTNAME}, {submitter_repr}!"
    login_url = federation_utils.full_url("/login")
    body = [
        f"Hi {submitter_repr} and welcome,",
        "",
        "Our moderation team has approved your account request and you can now start "
        "using the service. Please visit {} to get started.".format(login_url),
        "",
        "Before your first login, you may need to verify your e-mail address if you didn't already.",
    ]

    mail.send_mail(
        subject,
        message="\n".join(body),
        recipient_list=[submitter_email],
        from_email=settings.DEFAULT_FROM_EMAIL,
    )


def notify_submitter_signup_request_refused(user_request):
    submitter_repr = user_request.submitter.preferred_username
    submitter_email = user_request.submitter.user.email
    if not submitter_email:
        logger.warning("User %s has no e-mail address configured", submitter_repr)
        return
    subject = "Your account request at {} was refused".format(
        settings.FUNKWHALE_HOSTNAME
    )
    body = [
        f"Hi {submitter_repr},",
        "",
        "You recently submitted an account request on our service. However, our "
        "moderation team has refused it, and as a result, you won't be able to use "
        "the service.",
    ]

    instance_contact_email = preferences.get("instance__contact_email")
    if instance_contact_email:
        body += [
            "",
            "If you think this is a mistake, please contact our team at {}.".format(
                instance_contact_email
            ),
        ]

    mail.send_mail(
        subject,
        message="\n".join(body),
        recipient_list=[submitter_email],
        from_email=settings.DEFAULT_FROM_EMAIL,
    )
