"""
management command: verify_binary_integrity

Runs strict structural integrity checks on the company binary tree.

Checks performed:
    1. Orphan node detection
    2. Sponsor/binary mismatch reporting
    3. Invalid BFS placement detection
    4. Duplicate child slot detection
    5. Subtree corruption detection
    6. Cycle detection

Usage:
  python manage.py verify_binary_integrity
  python manage.py verify_binary_integrity --bundle <uuid>
  python manage.py verify_binary_integrity --fix-orphans
"""

from django.core.management.base import BaseCommand, CommandError

from apps.business.binary_tree.services.binary_service import verify_binary_integrity


class Command(BaseCommand):
    help = 'Verify binary tree structural integrity across all distributors.'

    def add_arguments(self, parser):
        parser.add_argument(
            '--bundle',
            type=str,
            default=None,
            help='Limit verification to a specific OpportunityBundle UUID.',
        )
        parser.add_argument(
            '--fix-orphans',
            action='store_true',
            default=False,
            help='(Not yet implemented) Attempt to auto-fix orphan mismatches.',
        )

    def handle(self, *args, **options):
        bundle_id = options.get('bundle')
        fix_orphans = options.get('fix_orphans', False)

        self.stdout.write(
            self.style.NOTICE(
                f"Running binary integrity check "
                f"(bundle={bundle_id or 'ALL'}, fix_orphans={fix_orphans}) ..."
            )
        )

        try:
            report = verify_binary_integrity(bundle_id=bundle_id)
        except Exception as exc:
            raise CommandError(f"Integrity check failed: {exc}") from exc

        total_issues = sum([
            len(report.get('cycles', [])),
            len(report.get('duplicate_child_slots', [])),
            len(report.get('invalid_positions', [])),
            len(report.get('orphan_nodes', [])),
            len(report.get('missing_parent_references', [])),
            len(report.get('multiple_roots', [])),
            len(report.get('bfs_inconsistencies', [])),
            len(report.get('subtree_corruption', {}).get('unreachable_nodes', [])),
        ])

        self.stdout.write(f"\n{'=' * 60}")
        self.stdout.write(f"Binary Integrity Report  (bundle={bundle_id or 'ALL'})")
        self.stdout.write(f"{'=' * 60}")
        self.stdout.write(f"  Distributors checked  : {report.get('checked', 0)}")
        self.stdout.write(f"  Cycles detected             : {len(report.get('cycles', []))}")
        self.stdout.write(f"  Orphan nodes                : {len(report.get('orphan_nodes', []))}")
        self.stdout.write(f"  Duplicate child slots       : {len(report.get('duplicate_child_slots', []))}")
        self.stdout.write(f"  Invalid positions           : {len(report.get('invalid_positions', []))}")
        self.stdout.write(f"  Missing parent references   : {len(report.get('missing_parent_references', []))}")
        self.stdout.write(f"  Multiple roots              : {len(report.get('multiple_roots', []))}")
        self.stdout.write(f"  Invalid BFS placements      : {len(report.get('bfs_inconsistencies', []))}")
        self.stdout.write(f"  Subtree corruption nodes    : {len(report.get('subtree_corruption', {}).get('unreachable_nodes', []))}")
        self.stdout.write(f"  Sponsor/Binary mismatches   : {len(report.get('sponsor_binary_mismatches', []))} (informational)")
        self.stdout.write(f"  Total issues          : {total_issues}")

        if total_issues == 0:
            self.stdout.write(self.style.SUCCESS("\nAll checks passed — tree is clean."))
        else:
            self.stdout.write(self.style.WARNING(f"\n{total_issues} issue(s) found. Details:"))

            for issue_type in (
                'cycles',
                'orphan_nodes',
                'duplicate_child_slots',
                'invalid_positions',
                'missing_parent_references',
                'multiple_roots',
                'bfs_inconsistencies',
            ):
                items = report.get(issue_type, [])
                if items:
                    self.stdout.write(f"\n  [{issue_type.upper()}]")
                    for item in items[:20]:
                        self.stdout.write(f"    - {item}")
                    if len(items) > 20:
                        self.stdout.write(f"    ... and {len(items) - 20} more")

                subtree_corruption = report.get('subtree_corruption', {})
                for issue_type in ('unreachable_nodes',):
                    items = subtree_corruption.get(issue_type, [])
                    if items:
                        self.stdout.write(f"\n  [SUBTREE_{issue_type.upper()}]")
                        for item in items[:20]:
                            self.stdout.write(f"    - {item}")
                        if len(items) > 20:
                            self.stdout.write(f"    ... and {len(items) - 20} more")

            sponsor_binary_mismatches = report.get('sponsor_binary_mismatches', [])
            if sponsor_binary_mismatches:
                self.stdout.write("\n  [SPONSOR_BINARY_MISMATCHES]")
                for item in sponsor_binary_mismatches[:20]:
                    self.stdout.write(f"    - {item}")
                if len(sponsor_binary_mismatches) > 20:
                    self.stdout.write(f"    ... and {len(sponsor_binary_mismatches) - 20} more")

            if fix_orphans:
                self.stdout.write(self.style.WARNING(
                    "\n--fix-orphans is not yet implemented. "
                    "Run backfill_binary_tree to re-seat unplaced nodes."
                ))
