"""
Automatically expire time-bound stock reservations past their expiry date,
releasing the held quantity back into available inventory.

Reservation expiry is otherwise *lazy* (only recalculated when a warehouse's
reservations are read). This command sweeps every warehouse so stock is released
promptly even when nobody is looking at that warehouse.

Run on a schedule, e.g. every 15 minutes:

  Linux cron:
    */15 * * * * cd /path/to/backend && /path/to/venv/bin/python manage.py expire_stock_reservations

  Windows Task Scheduler (repeat every 15 min):
    Program:   D:\\xampp\\htdocs\\megawatt-erp\\backend\\venv\\Scripts\\python.exe
    Arguments: manage.py expire_stock_reservations
    Start in:  D:\\xampp\\htdocs\\megawatt-erp\\backend

Available stock is computed as (on-hand - approved reservations), so flipping a
reservation to "expired" immediately returns its quantity to availability — no
inventory mutation is required.
"""
from django.core.management.base import BaseCommand
from django.utils import timezone

from megawatt_api.stock_webhook import notify_crm_stock
from warehouse_management.models import StockReservation, StockReservationInstance


class Command(BaseCommand):
    help = "Expire approved/pending stock reservations past their expiry date and release held stock."

    def handle(self, *args, **options):
        now = timezone.now()

        # Capture which products are freed by approved reservations *before*
        # flipping them, so we can broadcast the restored availability to the CRM.
        freed_product_ids = list(
            StockReservationInstance.objects.filter(
                stock_reservation__status="approved",
                stock_reservation__expiry_date__lt=now,
                stock_reservation__recycle_bin=False,
            ).values_list("product_id", flat=True)
        )

        # Approved reservations that have lapsed → release the held stock.
        approved_expired = StockReservation.objects.filter(
            status="approved",
            expiry_date__lt=now,
            recycle_bin=False,
        ).update(status="expired")

        # Pending requests that lapsed before a decision → mark expired too.
        pending_expired = StockReservation.objects.filter(
            status="pending",
            expiry_date__lt=now,
            recycle_bin=False,
        ).update(status="expired")

        # Broadcast restored availability for products whose held stock was freed.
        if approved_expired and freed_product_ids:
            notify_crm_stock(set(freed_product_ids))

        total = approved_expired + pending_expired
        self.stdout.write(self.style.SUCCESS(
            f"Expired {total} reservation(s) — {approved_expired} approved (stock released), "
            f"{pending_expired} pending."
        ))
