from datetime import date, timedelta

from django.core.management.base import BaseCommand, CommandError
from django.utils import timezone

from market.models import FarmerMarketListing
from market.services import (
    notify_farmer_market_expiring_soon,
    notify_farmer_market_listing_expired,
)


class Command(BaseCommand):
    help = "Send expiry reminders and update grace-period state for farmer-hosted market listings."

    def add_arguments(self, parser):
        parser.add_argument(
            "--date",
            dest="run_date",
            help="Optional YYYY-MM-DD date override for cron backfills.",
        )
        parser.add_argument(
            "--dry-run",
            action="store_true",
            help="Preview the listings that would be updated without saving changes.",
        )

    def handle(self, *args, **options):
        run_date = self._parse_run_date(options.get("run_date"))
        dry_run = bool(options.get("dry_run"))
        now = timezone.now()

        listings = FarmerMarketListing.objects.select_related("farmer", "field_officer", "category").filter(
            status__in=[FarmerMarketListing.Status.LIVE, FarmerMarketListing.Status.EXPIRED],
            visible_until__isnull=False,
        )

        expiring_rows = list(
            listings.filter(
                status=FarmerMarketListing.Status.LIVE,
                visible_until=run_date + timedelta(days=2),
                expiry_warning_sent_at__isnull=True,
            )
        )
        expired_rows = list(
            listings.filter(
                visible_until__lt=run_date,
                expired_notice_sent_at__isnull=True,
            )
        )
        stale_live_rows = list(
            listings.filter(
                status=FarmerMarketListing.Status.LIVE,
                visible_until__lt=run_date,
            )
        )
        hidden_rows = list(
            listings.filter(
                grace_until__lt=run_date,
            )
        )

        for listing in expiring_rows:
            if dry_run:
                continue
            notify_farmer_market_expiring_soon(listing)
            listing.expiry_warning_sent_at = now
            listing.save(update_fields=["expiry_warning_sent_at", "updated_at"])

        for listing in expired_rows:
            if dry_run:
                continue
            notify_farmer_market_listing_expired(listing)
            listing.status = FarmerMarketListing.Status.EXPIRED
            listing.expired_notice_sent_at = now
            listing.save(update_fields=["status", "expired_notice_sent_at", "updated_at"])

        expired_ids = {listing.id for listing in expired_rows}
        for listing in stale_live_rows:
            if dry_run or listing.id in expired_ids:
                continue
            listing.status = FarmerMarketListing.Status.EXPIRED
            listing.save(update_fields=["status", "updated_at"])

        summary = (
            f"Farmer listing expiry processing for {run_date}: "
            f"warnings={len(expiring_rows)}, "
            f"expired_notices={len(expired_rows)}, "
            f"marked_expired={len(stale_live_rows)}, "
            f"hidden_after_grace={len(hidden_rows)}"
        )
        if dry_run:
            self.stdout.write(self.style.WARNING(f"Dry run only. {summary}"))
            return

        self.stdout.write(self.style.SUCCESS(summary))

    def _parse_run_date(self, raw_value):
        if not raw_value:
            return timezone.now().date()
        try:
            return date.fromisoformat(str(raw_value).strip())
        except ValueError as exc:
            raise CommandError("Use --date in YYYY-MM-DD format.") from exc
