"""
Management command to backfill monthly physician ratings from existing
individual ratings that have not yet been aggregated.

Usage:
    python manage.py backfill_physician_monthly_ratings
    python manage.py backfill_physician_monthly_ratings --year 2026 --month 4
    python manage.py backfill_physician_monthly_ratings --dry-run
"""

import logging
from typing import Optional

from django.core.management.base import BaseCommand

from apps.physicians.adapter import DoctorRatingAdapter
from apps.physicians.models import PhysicianIndividualRating
from apps.organizations.models import Hospital

logger = logging.getLogger(__name__)


class Command(BaseCommand):
    help = "Backfill PhysicianMonthlyRating aggregates from unaggregated PhysicianIndividualRating records"

    def add_arguments(self, parser):
        parser.add_argument("--year", type=int, help="Specific year to backfill (e.g. 2026)")
        parser.add_argument("--month", type=int, help="Specific month to backfill (1-12)")
        parser.add_argument("--hospital-id", type=str, help="Optional hospital UUID to limit backfill")
        parser.add_argument(
            "--dry-run",
            action="store_true",
            help="Show what would be aggregated without saving changes",
        )

    def handle(self, *args, **options):
        year: Optional[int] = options.get("year")
        month: Optional[int] = options.get("month")
        hospital_id: Optional[str] = options.get("hospital_id")
        dry_run: bool = options["dry_run"]

        hospital = None
        if hospital_id:
            try:
                hospital = Hospital.objects.get(id=hospital_id)
            except Hospital.DoesNotExist:
                self.stdout.write(self.style.ERROR(f"Hospital {hospital_id} not found"))
                return

        # Build queryset of unaggregated records
        qs = PhysicianIndividualRating.objects.filter(is_aggregated=False)
        if year:
            qs = qs.filter(rating_date__year=year)
        if month:
            qs = qs.filter(rating_date__month=month)
        if hospital:
            qs = qs.filter(hospital=hospital)

        total_unaggregated = qs.count()
        if total_unaggregated == 0:
            self.stdout.write(self.style.SUCCESS("No unaggregated individual ratings found."))
            return

        self.stdout.write(f"Found {total_unaggregated} unaggregated individual rating(s).")

        # Determine distinct periods/hospitals to process
        periods = (
            qs.values("rating_date__year", "rating_date__month", "hospital")
            .distinct()
            .order_by("rating_date__year", "rating_date__month", "hospital")
        )

        total_aggregated = 0
        total_skipped = 0
        total_errors = 0

        for period in periods:
            p_year = period["rating_date__year"]
            p_month = period["rating_date__month"]
            p_hospital_id = period["hospital"]

            p_hospital = None
            if p_hospital_id:
                try:
                    p_hospital = Hospital.objects.get(id=p_hospital_id)
                except Hospital.DoesNotExist:
                    self.stdout.write(
                        self.style.WARNING(f"Skipping {p_year}-{p_month:02d} hospital {p_hospital_id} (not found)")
                    )
                    continue

            label = f"{p_year}-{p_month:02d}"
            if p_hospital:
                label += f" ({p_hospital.name})"

            if dry_run:
                count = qs.filter(
                    rating_date__year=p_year,
                    rating_date__month=p_month,
                    hospital=p_hospital_id,
                ).count()
                self.stdout.write(f"[DRY RUN] Would aggregate {count} rating(s) for {label}")
                continue

            self.stdout.write(f"Aggregating {label} ...")
            results = DoctorRatingAdapter.aggregate_monthly_ratings(year=p_year, month=p_month, hospital=p_hospital)
            total_aggregated += results["aggregated"]
            total_skipped += results.get("skipped_unlinked", 0)
            total_errors += len(results["errors"])

            self.stdout.write(
                f"  -> Aggregated: {results['aggregated']}, "
                f"Skipped (unlinked): {results.get('skipped_unlinked', 0)}, "
                f"Errors: {len(results['errors'])}"
            )

        if not dry_run:
            self.stdout.write(
                self.style.SUCCESS(
                    f"\nBackfill complete: {total_aggregated} monthly record(s) updated, "
                    f"{total_skipped} unlinked rating(s) skipped, "
                    f"{total_errors} error(s)."
                )
            )
        else:
            self.stdout.write(self.style.NOTICE("\nDry run complete. No changes were saved."))
