"""
Admin Binary Analysis Views
===========================

GET  /api/v1/admin/binary-analysis/
     Paginated list of all distributors with binary metrics + level data.

GET  /api/v1/admin/binary-analysis/<distributor_id>/
     Full binary detail for one distributor.

GET  /api/v1/admin/binary-tree/<distributor_id>/
     Deep tree structure (admin can request up to depth 15).

POST /api/v1/admin/binary-rebuild/
     Trigger on-demand full rebuild of binary metrics.

GET  /api/v1/admin/binary-integrity/
     Run integrity scan and return report.

GET  /api/v1/admin/power-stream-forfeiture/
     List all power stream forfeiture logs.
"""

from rest_framework import permissions, status
from rest_framework.response import Response
from rest_framework.views import APIView

from apps.business.binary_tree.models import BinaryTreeMetrics, PowerStreamForfeitureLog
from apps.business.binary_tree.services.binary_service import (
    build_binary_subtree_dict,
    verify_binary_integrity,
)
from apps.business.binary_tree.services.metrics_service import (
    compute_and_persist_all,
    get_binary_dashboard_data,
)
from apps.business.distributor.models import DistributorID


class AdminBinaryAnalysisListView(APIView):
    """
    GET /api/v1/admin/binary-analysis/

    Query params:
      opportunity_bundle — filter by bundle UUID
      search             — match user name / email / distributor_code
      page               — 1-based (default 1)
      page_size          — default 50, max 200
      imbalance_min      — filter where imbalance_ratio >= value
      weak_leg           — 'LEFT' | 'RIGHT' | 'BALANCED'
    """
    permission_classes = [permissions.IsAdminUser]

    def get(self, request):
        qs = DistributorID.objects.select_related(
            'user', 'product__opportunity_bundle', 'binary_metrics',
        ).order_by('global_position')

        bundle_id = request.query_params.get('opportunity_bundle')
        if bundle_id:
            qs = qs.filter(product__opportunity_bundle_id=bundle_id)

        search = request.query_params.get('search', '').strip()
        if search:
            from django.db.models import Q
            qs = qs.filter(
                Q(user__first_name__icontains=search)
                | Q(user__last_name__icontains=search)
                | Q(user__email__icontains=search)
                | Q(distributor_code__icontains=search)
            )

        imbalance_min = request.query_params.get('imbalance_min')
        if imbalance_min:
            try:
                qs = qs.filter(binary_metrics__imbalance_ratio__gte=float(imbalance_min))
            except (ValueError, TypeError):
                pass

        weak_leg = request.query_params.get('weak_leg')
        if weak_leg in ('LEFT', 'RIGHT', 'BALANCED'):
            qs = qs.filter(binary_metrics__weak_leg=weak_leg)

        # Paginate
        try:
            page = max(1, int(request.query_params.get('page', 1)))
            page_size = min(200, int(request.query_params.get('page_size', 50)))
        except (TypeError, ValueError):
            page, page_size = 1, 50

        total = qs.count()
        offset = (page - 1) * page_size
        distributors = qs[offset: offset + page_size]

        results = []
        for dist in distributors:
            try:
                metrics = getattr(dist, 'binary_metrics', None)
                user = dist.user
                results.append({
                    'id': str(dist.id),
                    'distributor_code': dist.distributor_code,
                    'global_position': dist.global_position,
                    'is_active': dist.is_active,
                    'user_id': str(user.id),
                    'user_name': (
                        f"{getattr(user, 'first_name', '') or ''} "
                        f"{getattr(user, 'last_name', '') or ''}".strip()
                        or str(user)
                    ),
                    'user_email': getattr(user, 'email', '') or '',
                    'product_name': dist.product.name if dist.product else None,
                    'opportunity_bundle': (
                        dist.product.opportunity_bundle.name
                        if dist.product and dist.product.opportunity_bundle else None
                    ),
                    'left_volume': metrics.left_volume if metrics else None,
                    'right_volume': metrics.right_volume if metrics else None,
                    'subtree_total': metrics.subtree_total if metrics else None,
                    'weak_leg': metrics.weak_leg if metrics else None,
                    'imbalance_ratio': str(metrics.imbalance_ratio) if metrics else None,
                    'has_metrics': metrics is not None,
                    'binary_parent_id': str(dist.binary_parent_distributor_id) if dist.binary_parent_distributor_id else None,
                    'binary_position': dist.binary_position,
                })
            except Exception as exc:
                results.append({'id': str(dist.id), 'error': str(exc)})

        return Response({
            'success': True,
            'data': results,
            'pagination': {
                'total': total,
                'page': page,
                'page_size': page_size,
                'total_pages': (total + page_size - 1) // page_size,
            },
        })


class AdminBinaryAnalysisDetailView(APIView):
    """GET /api/v1/admin/binary-analysis/<distributor_id>/"""
    permission_classes = [permissions.IsAdminUser]

    def get(self, request, distributor_id):
        try:
            dist = DistributorID.objects.select_related(
                'user', 'product__opportunity_bundle'
            ).get(pk=distributor_id)
        except DistributorID.DoesNotExist:
            return Response({'success': False, 'error': 'Not found.'}, status=404)

        data = get_binary_dashboard_data(dist)
        return Response({'success': True, 'data': data})


class AdminBinaryTreeView(APIView):
    """GET /api/v1/admin/binary-tree/<distributor_id>/?depth=<1-15>"""
    permission_classes = [permissions.IsAdminUser]

    def get(self, request, distributor_id):
        try:
            DistributorID.objects.get(pk=distributor_id)
        except DistributorID.DoesNotExist:
            return Response({'success': False, 'error': 'Not found.'}, status=404)

        try:
            depth = min(int(request.query_params.get('depth', 8)), 15)
        except (TypeError, ValueError):
            depth = 8

        tree = build_binary_subtree_dict(distributor_id, max_depth=depth)
        return Response({'success': True, 'data': {'tree': tree, 'depth_rendered': depth}})


class AdminBinaryRebuildView(APIView):
    """POST /api/v1/admin/binary-rebuild/ — trigger on-demand full rebuild."""
    permission_classes = [permissions.IsAdminUser]

    def post(self, request):
        from apps.business.binary_tree.tasks import rebuild_binary_tree_metrics_task
        bundle_id = request.data.get('opportunity_bundle')
        rebuild_binary_tree_metrics_task.delay(bundle_id=bundle_id, only_stale=False)
        return Response({
            'success': True,
            'message': 'Binary metrics rebuild queued.',
            'bundle_id': bundle_id,
        })


class AdminBinaryIntegrityView(APIView):
    """GET /api/v1/admin/binary-integrity/ — run integrity scan synchronously."""
    permission_classes = [permissions.IsAdminUser]

    def get(self, request):
        bundle_id = request.query_params.get('opportunity_bundle')
        report = verify_binary_integrity(bundle_id=bundle_id)
        return Response({'success': True, 'data': report})


class AdminPowerStreamForfeitureView(APIView):
    """
    GET /api/v1/admin/power-stream-forfeiture/

    Query params: user_id, page, page_size
    """
    permission_classes = [permissions.IsAdminUser]

    def get(self, request):
        qs = PowerStreamForfeitureLog.objects.select_related('user', 'bonus_record').order_by('-forfeited_at')

        user_id = request.query_params.get('user_id')
        if user_id:
            qs = qs.filter(user_id=user_id)

        try:
            page = max(1, int(request.query_params.get('page', 1)))
            page_size = min(200, int(request.query_params.get('page_size', 50)))
        except (TypeError, ValueError):
            page, page_size = 1, 50

        total = qs.count()
        offset = (page - 1) * page_size
        rows = qs[offset: offset + page_size]

        data = []
        for row in rows:
            user = row.user
            data.append({
                'id': str(row.id),
                'user_id': str(user.id),
                'user_name': (
                    f"{getattr(user, 'first_name', '') or ''} "
                    f"{getattr(user, 'last_name', '') or ''}".strip()
                    or str(user)
                ),
                'user_email': getattr(user, 'email', '') or '',
                'gross_amount': str(row.gross_amount),
                'net_amount': str(row.net_amount),
                'forfeited_at': row.forfeited_at.isoformat(),
                'reason': row.reason,
                'grace_expired': row.grace_expired,
                'bonus_level': row.bonus_record.level if row.bonus_record else None,
            })

        return Response({
            'success': True,
            'data': data,
            'pagination': {
                'total': total,
                'page': page,
                'page_size': page_size,
                'total_pages': (total + page_size - 1) // page_size,
            },
        })
