"""
management command: rebuild_binary_metrics

Rebuilds BinaryTreeMetrics + BinaryLevelSnapshot for all (or stale) distributors.
Results are also mirrored into DistributorLevelProgress so existing APIs remain
accurate.

Usage:
  python manage.py rebuild_binary_metrics
  python manage.py rebuild_binary_metrics --bundle <uuid>
  python manage.py rebuild_binary_metrics --stale-only
  python manage.py rebuild_binary_metrics --distributor <uuid>
"""

from django.core.management.base import BaseCommand, CommandError


class Command(BaseCommand):
    help = 'Rebuild binary tree metrics and level snapshots.'

    def add_arguments(self, parser):
        parser.add_argument(
            '--bundle',
            type=str,
            default=None,
            help='Limit rebuild to a specific OpportunityBundle UUID.',
        )
        parser.add_argument(
            '--stale-only',
            action='store_true',
            default=False,
            help='Only process distributors whose metrics are >24 h old.',
        )
        parser.add_argument(
            '--distributor',
            type=str,
            default=None,
            help='Rebuild for a single DistributorID UUID.',
        )

    def handle(self, *args, **options):
        bundle_id = options.get('bundle')
        stale_only = options.get('stale_only', False)
        distributor_id = options.get('distributor')

        if distributor_id:
            self._rebuild_single(distributor_id)
        else:
            self._rebuild_all(bundle_id=bundle_id, stale_only=stale_only)

    # ------------------------------------------------------------------

    def _rebuild_single(self, distributor_id: str):
        from apps.business.distributor.models import DistributorID
        from apps.business.binary_tree.services.metrics_service import (
            compute_metrics_for_distributor,
            compute_binary_level_snapshot,
        )

        try:
            dist = DistributorID.objects.get(pk=distributor_id)
        except DistributorID.DoesNotExist:
            raise CommandError(f"DistributorID {distributor_id} not found.")

        self.stdout.write(self.style.NOTICE(f"Rebuilding metrics for {distributor_id} ..."))

        try:
            metrics = compute_metrics_for_distributor(dist)
            snapshot = compute_binary_level_snapshot(dist)
            self.stdout.write(self.style.SUCCESS(
                f"Done.\n"
                f"  left_volume  = {metrics.left_volume}\n"
                f"  right_volume = {metrics.right_volume}\n"
                f"  weak_leg     = {metrics.weak_leg}\n"
                f"  current_level= {snapshot.current_level}"
            ))
        except Exception as exc:
            raise CommandError(f"Rebuild failed: {exc}") from exc

    def _rebuild_all(self, bundle_id=None, stale_only=False):
        from apps.business.binary_tree.services.metrics_service import compute_and_persist_all

        self.stdout.write(
            self.style.NOTICE(
                f"Rebuilding ALL binary metrics "
                f"(bundle={bundle_id or 'ALL'}, stale_only={stale_only}) ..."
            )
        )

        try:
            result = compute_and_persist_all(bundle_id=bundle_id, only_stale=stale_only)
        except Exception as exc:
            raise CommandError(f"Rebuild failed: {exc}") from exc

        self.stdout.write(self.style.SUCCESS(
            f"\nRebuild complete:\n"
            f"  Processed  : {result.get('processed', 0)}\n"
            f"  Skipped    : {result.get('skipped', 0)}\n"
            f"  Errors     : {result.get('errors', 0)}"
        ))

        if result.get('errors', 0) > 0:
            self.stdout.write(self.style.WARNING(
                "WARNING: some distributors could not be processed. "
                "Check application logs for details."
            ))
