import logging
from datetime import UTC, datetime, timedelta

from django.conf import settings
from django.contrib.auth.models import User
from django.core.management.base import BaseCommand

from privaterelay.management.utils import (
    get_free_phone_social_accounts,
    get_phone_subscriber_social_accounts,
)
from privaterelay.models import Profile

if settings.PHONES_ENABLED:
    from phones.models import RelayNumber

logger = logging.getLogger("events")


def reset_phone_remaining_stats(user: User) -> None:
    # re-set remaining_texts and remaining_seconds to the maximum value
    try:
        relay_number = RelayNumber.objects.get(user=user)
    except RelayNumber.DoesNotExist:
        # no RelayNumber set, do nothing
        return
    relay_number.remaining_texts = settings.MAX_TEXTS_PER_BILLING_CYCLE
    relay_number.remaining_seconds = settings.MAX_MINUTES_PER_BILLING_CYCLE * 60
    relay_number.save()


def get_next_reset_date(profile: Profile) -> datetime:
    # TODO: consider moving this as a property in Profile model
    # assumes that profile being passed have already been checked to have
    # phone subscription or a free phone user
    if profile.date_phone_subscription_reset is None:
        # there is a problem with the sync_phone_related_dates_on_profile
        # or a new foxfooder whose date_phone_subscription_reset did not get set in
        if profile.fxa:
            fxa_uid = profile.fxa.uid
        else:
            fxa_uid = "None"
        logger.error(
            "phone_user_profile_dates_not_set",
            extra={
                "fxa_uid": fxa_uid,
                "date_subscribed_phone": profile.date_phone_subscription_end,
                "date_phone_subscription_start": profile.date_phone_subscription_start,
                "date_phone_subscription_reset": profile.date_phone_subscription_reset,
                "date_phone_subscription_end": profile.date_phone_subscription_end,
            },
        )
        return datetime.now(UTC) - timedelta(minutes=15)

    calculated_next_reset_date = profile.date_phone_subscription_reset + timedelta(
        settings.MAX_DAYS_IN_MONTH
    )
    if profile.date_phone_subscription_end is None:
        return calculated_next_reset_date
    if profile.date_phone_subscription_end < calculated_next_reset_date:
        # return the past or the closest next reset date
        return profile.date_phone_subscription_end
    return calculated_next_reset_date


def update_phone_remaining_stats() -> tuple[int, int]:
    social_accounts_with_phones = get_phone_subscriber_social_accounts()
    free_phones_social_accounts = get_free_phone_social_accounts()
    social_accounts_with_phones.update(free_phones_social_accounts)

    if not settings.PHONES_ENABLED or len(social_accounts_with_phones) == 0:
        return 0, 0

    updated_profiles = []
    datetime_now = datetime.now(UTC)
    for social_account in social_accounts_with_phones:
        profile = social_account.user.profile
        next_reset_date = get_next_reset_date(profile)
        if next_reset_date > datetime_now:
            continue
        # next reset day is now or in the past
        reset_phone_remaining_stats(profile.user)
        profile.date_phone_subscription_reset = datetime_now
        profile.save()
        updated_profiles.append(profile)
    return len(social_accounts_with_phones), len(updated_profiles)


class Command(BaseCommand):
    help = "Update all phone users' subscription and stats."

    def handle(self, *args, **options):
        num_profiles_w_phones, num_profiles_updated = update_phone_remaining_stats()
        print(
            f"Out of {num_profiles_w_phones} profiles,"
            f" {num_profiles_updated} limits were reset"
        )
