"""
Обработка отложенных бонусов за рефералов.

Начисление возможно только при выполнении одного из условий:
- Прошло 30+ дней с приглашения И реферал был активен 20+ дней;
- Реферал был активен 21+ день (независимо от срока).

Запуск: python manage.py process_pending_referral_bonuses
Рекомендуется добавить в cron (ежедневно).
"""
from django.core.management.base import BaseCommand
from django.utils import timezone
from django.db import transaction

from apps.referrals.models import (
    PendingReferralBonus,
    UserActivityDay,
    UserReferralProfile,
)


class Command(BaseCommand):
    help = 'Начислить бонусы за рефералов, выполнивших условия по активности (20+ дней за 30 дней или 21+ день всего)'

    def add_arguments(self, parser):
        parser.add_argument(
            '--dry-run',
            action='store_true',
            help='Только показать, что было бы начислено, без изменений в БД',
        )

    def handle(self, *args, **options):
        dry_run = options['dry_run']
        now = timezone.now()
        paid_count = 0
        for pending in PendingReferralBonus.objects.filter(status=PendingReferralBonus.STATUS_PENDING).select_related(
            'referrer', 'referred_user'
        ):
            referred_at = pending.referred_at
            referred_date = referred_at.date()
            # Дней активности реферала с даты приглашения
            active_days = UserActivityDay.objects.filter(
                user=pending.referred_user,
                date__gte=referred_date,
            ).count()
            days_since_referral = (now - referred_at).days
            past_30 = days_since_referral >= 30
            # Условие: (30+ дней и 20+ активных) ИЛИ (21+ активных дней)
            if (past_30 and active_days >= 20) or (active_days >= 21):
                if dry_run:
                    self.stdout.write(
                        f'[dry-run] Начислили бы {pending.points} очков {pending.referrer.email} '
                        f'за реферала {pending.referred_user.email} (активных дней: {active_days}, прошло дней: {days_since_referral})'
                    )
                    paid_count += 1
                    continue
                try:
                    with transaction.atomic():
                        referrer_profile = pending.referrer.referral_profile
                        referrer_profile.add_points(pending.points, reason=pending.reason or f'Реферал {pending.referred_user.email} выполнил условия активности')
                        pending.status = PendingReferralBonus.STATUS_PAID
                        pending.paid_at = now
                        pending.save(update_fields=['status', 'paid_at'])
                    paid_count += 1
                    self.stdout.write(
                        self.style.SUCCESS(
                            f'Начислено {pending.points} очков {pending.referrer.email} за {pending.referred_user.email} (активных дней: {active_days})'
                        )
                    )
                except UserReferralProfile.DoesNotExist:
                    self.stdout.write(
                        self.style.WARNING(f'Пропуск {pending.id}: у реферера нет профиля')
                    )
                except Exception as e:
                    self.stdout.write(
                        self.style.ERROR(f'Ошибка при начислении {pending.id}: {e}')
                    )
        if dry_run:
            self.stdout.write(self.style.SUCCESS(f'[dry-run] Всего к начислению: {paid_count}'))
        else:
            self.stdout.write(self.style.SUCCESS(f'Начислено бонусов: {paid_count}'))
