from collections.abc import Callable

from django.http import HttpRequest, HttpResponse
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt

from confirmation.models import Confirmation, ConfirmationKeyError, get_object_from_key
from zerver.actions.user_settings import do_change_user_setting
from zerver.context_processors import common_context
from zerver.lib.send_email import clear_scheduled_emails
from zerver.models import ScheduledEmail, UserProfile


def process_unsubscribe(
    request: HttpRequest,
    confirmation_key: str,
    subscription_type: str,
    unsubscribe_function: Callable[[UserProfile], None],
) -> HttpResponse:
    try:
        user_profile = get_object_from_key(
            confirmation_key, [Confirmation.UNSUBSCRIBE], mark_object_used=False
        )
    except ConfirmationKeyError:
        return render(request, "zerver/unsubscribe_link_error.html")

    assert isinstance(user_profile, UserProfile)
    unsubscribe_function(user_profile)
    context = common_context(user_profile)
    context.update(subscription_type=subscription_type)
    return render(request, "zerver/unsubscribe_success.html", context=context)


# Email unsubscribe functions. All have the function signature
# processor(user_profile).


def do_missedmessage_unsubscribe(user_profile: UserProfile) -> None:
    do_change_user_setting(
        user_profile, "enable_offline_email_notifications", False, acting_user=user_profile
    )


def do_welcome_unsubscribe(user_profile: UserProfile) -> None:
    clear_scheduled_emails([user_profile.id], ScheduledEmail.WELCOME)


def do_digest_unsubscribe(user_profile: UserProfile) -> None:
    do_change_user_setting(user_profile, "enable_digest_emails", False, acting_user=user_profile)


def do_login_unsubscribe(user_profile: UserProfile) -> None:
    do_change_user_setting(user_profile, "enable_login_emails", False, acting_user=user_profile)


def do_marketing_unsubscribe(user_profile: UserProfile) -> None:
    do_change_user_setting(user_profile, "enable_marketing_emails", False, acting_user=user_profile)


# The keys are part of the URL for the unsubscribe link and must be valid
# without encoding.
# The values are a tuple of (display name, unsubscribe function), where the
# display name is what we call this class of email in user-visible text.
email_unsubscribers = {
    "missed_messages": ("missed messages", do_missedmessage_unsubscribe),
    "welcome": ("welcome", do_welcome_unsubscribe),
    "digest": ("digest", do_digest_unsubscribe),
    "login": ("login", do_login_unsubscribe),
    "marketing": ("marketing", do_marketing_unsubscribe),
}


# Login NOT required. These are for one-click unsubscribes.
@csrf_exempt
def email_unsubscribe(request: HttpRequest, email_type: str, confirmation_key: str) -> HttpResponse:
    if email_type in email_unsubscribers:
        display_name, unsubscribe_function = email_unsubscribers[email_type]
        return process_unsubscribe(request, confirmation_key, display_name, unsubscribe_function)

    return render(request, "zerver/unsubscribe_link_error.html")
