# subscriptions/management/commands/process_subscriptions.py
"""
Management command: process subscription lifecycle tasks.

Run daily via cron/Task Scheduler:
  python manage.py process_subscriptions

Tasks:
1. Apply pending downgrades (when current subscription has expired)
2. Deactivate expired subscriptions
3. Send expiry warning emails (3 days before)
4. Send trial expiry warnings (1 day before)
"""
import logging
from datetime import date, timedelta

from django.core.management.base import BaseCommand
from django.db import transaction as db_transaction

from subscriptions.models import Subscription

logger = logging.getLogger(__name__)


class Command(BaseCommand):
    help = "Process subscription lifecycle: downgrades, expiry deactivation, email warnings"

    def handle(self, *args, **options):
        today = date.today()
        self.stdout.write(f"[{today}] Processing subscriptions...")

        self._apply_pending_downgrades(today)
        self._deactivate_expired(today)
        self._send_expiry_warnings(today)

        self.stdout.write(self.style.SUCCESS(f"[{today}] Subscription processing complete."))

    # ──────────────────────────────────────────────────────────────────────────
    # 1. APPLY PENDING DOWNGRADES
    # ──────────────────────────────────────────────────────────────────────────
    @db_transaction.atomic
    def _apply_pending_downgrades(self, today):
        """Apply scheduled downgrades where current subscription has expired."""
        subs = Subscription.objects.filter(
            is_active=True,
            pending_downgrade_plan__isnull=False,
            expiry_date__lt=today,
        ).select_related('company', 'plan', 'pending_downgrade_plan')

        count = 0
        for sub in subs:
            new_plan = sub.pending_downgrade_plan
            company = sub.company

            # Deactivate current subscription
            sub.is_active = False
            sub.save(update_fields=['is_active'])

            # Create new subscription for the downgraded plan
            from datetime import timedelta
            from subscriptions.models import BILLING_CYCLE_DAYS
            new_expiry = today + timedelta(days=BILLING_CYCLE_DAYS.get(sub.billing_cycle, 30))
            
            new_sub = Subscription.objects.create(
                company=company,
                plan=new_plan,
                billing_cycle=sub.billing_cycle,
                start_date=today,
                expiry_date=new_expiry,
                is_trial=False,
                is_active=True,
                payment_status='paid',  # Downgrade at end of cycle, no new payment
            )

            # Sync company
            company.plan = new_plan
            company.expiry_date = new_expiry
            company.save(update_fields=['plan', 'expiry_date'])

            logger.info(
                f"⬇️ Downgrade applied: company={company.slug}, "
                f"from={sub.plan.name}, to={new_plan.name}"
            )
            count += 1

        self.stdout.write(f"  Applied {count} pending downgrade(s).")

    # ──────────────────────────────────────────────────────────────────────────
    # 2. DEACTIVATE EXPIRED SUBSCRIPTIONS
    # ──────────────────────────────────────────────────────────────────────────
    def _deactivate_expired(self, today):
        """Deactivate expired subscriptions (no pending downgrade)."""
        expired = Subscription.objects.filter(
            is_active=True,
            expiry_date__lt=today,
            pending_downgrade_plan__isnull=True,
        ).select_related('company')

        count = 0
        for sub in expired:
            sub.is_active = False
            sub.save(update_fields=['is_active'])
            # Also deactivate the company if no active subscription
            company = sub.company
            if not Subscription.objects.filter(company=company, is_active=True).exists():
                company.is_active = False
                company.save(update_fields=['is_active'])
                logger.warning(f"🔴 Company deactivated (expired): {company.slug}")
            count += 1
        self.stdout.write(f"  Deactivated {count} expired subscription(s).")

    # ──────────────────────────────────────────────────────────────────────────
    # 3. SEND EXPIRY WARNINGS
    # ──────────────────────────────────────────────────────────────────────────
    def _send_expiry_warnings(self, today):
        """Email companies whose subscription expires in 3 days or 1 day."""
        warning_days = [3, 1]
        count = 0

        for days in warning_days:
            target_date = today + timedelta(days=days)
            subs = Subscription.objects.filter(
                is_active=True,
                expiry_date=target_date,
            ).select_related('company', 'plan')

            for sub in subs:
                self._send_expiry_email(sub, days)
                count += 1

        self.stdout.write(f"  Sent {count} expiry warning email(s).")

    def _send_expiry_email(self, sub, days_left):
        """Send expiry warning email to company admin."""
        company = sub.company
        admin_user = company.users.filter(role='admin').first()
        if not admin_user or not admin_user.email:
            return

        label = "trial" if sub.is_trial else "subscription"
        try:
            from django.core.mail import send_mail
            from django.conf import settings as djsettings

            subject = f"⚠️ Your SwiftPOS {label} expires in {days_left} day(s) — {company.name}"
            message = (
                f"Hi {admin_user.first_name or admin_user.username},\n\n"
                f"Your SwiftPOS {label} for {company.name} will expire in {days_left} day(s) "
                f"on {sub.expiry_date.strftime('%d %B %Y')}.\n\n"
                f"Current plan: {sub.plan.name}\n\n"
                f"To continue using SwiftPOS, please renew or upgrade your subscription at:\n"
                f"https://swiftpos.app/{company.slug}/subscription/manage/\n\n"
                f"Or contact us on WhatsApp: https://wa.me/{getattr(djsettings, 'WHATSAPP_NUMBER', '')}\n\n"
                f"Thank you for using SwiftPOS!\n"
            )
            send_mail(
                subject=subject,
                message=message,
                from_email=djsettings.DEFAULT_FROM_EMAIL,
                recipient_list=[admin_user.email],
                fail_silently=True,
            )
            logger.info(f"📧 Expiry warning sent to {admin_user.email} ({days_left} days)")
        except Exception as e:
            logger.error(f"Failed to send expiry email to {company.slug}: {e}")
