"""
Binary Analysis API Views (Web / User-facing)

GET /api/v1/web/binary-analysis/
    Returns binary tree metrics + level progress for all of the authenticated
    user's distributor IDs.

GET /api/v1/web/binary-analysis/<distributor_id>/
    Detailed binary dashboard for a specific distributor ID.

GET /api/v1/web/binary-tree/<distributor_id>/
    Nested binary tree structure (up to 8 levels deep) for visualization.

GET /api/v1/web/binary-progress/
    Level progress summary (binary-based) for all user distributor IDs.
"""

from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from apps.business.distributor.models import DistributorID
from apps.business.binary_tree.services.metrics_service import (
    compute_binary_level_snapshot,
    compute_metrics_for_distributor,
    get_binary_dashboard_data,
    upsert_metrics,
)
from apps.business.binary_tree.services.binary_service import (
    build_binary_subtree_dict,
    get_binary_left_right_volumes,
)
from apps.business.binary_tree.models import BinaryTreeMetrics, BinaryLevelSnapshot
from apps.business.schema_compat import defer_missing_product_part_payment_fields


class BinaryAnalysisSummaryView(APIView):
    """
    GET /api/v1/web/binary-analysis/

    Returns binary metrics for all distributor IDs owned by the user.
    """
    permission_classes = [IsAuthenticated]

    def get(self, request):
        user = request.user
        distributors = list(
            defer_missing_product_part_payment_fields(
                DistributorID.objects.filter(user=user)
                .select_related('product__opportunity_bundle', 'binary_metrics')
                .order_by('created_at'),
                relation_prefix='product',
            )
        )

        if not distributors:
            return Response({'success': True, 'data': []})

        results = []
        for dist in distributors:
            try:
                data = get_binary_dashboard_data(dist)
                results.append(data)
            except Exception as exc:
                results.append({
                    'distributor_id': str(dist.id),
                    'distributor_code': dist.distributor_code,
                    'error': str(exc),
                })

        return Response({'success': True, 'data': results})


class BinaryAnalysisDetailView(APIView):
    """
    GET /api/v1/web/binary-analysis/<distributor_id>/

    Detailed binary dashboard + actionable hints for one distributor ID.
    """
    permission_classes = [IsAuthenticated]

    def get(self, request, distributor_id):
        try:
            dist = defer_missing_product_part_payment_fields(
                DistributorID.objects.select_related(
                    'product__opportunity_bundle', 'binary_metrics', 'user'
                ),
                relation_prefix='product',
            ).get(pk=distributor_id, user=request.user)
        except DistributorID.DoesNotExist:
            return Response({'success': False, 'error': 'Distributor ID not found.'}, status=404)

        data = get_binary_dashboard_data(dist)

        # Enrich with sponsor referral counts (left / right direct children via sponsor)
        left_via_sponsor = DistributorID.objects.filter(
            sponsor_distributor=dist,
            binary_position='LEFT',
        ).count()
        right_via_sponsor = DistributorID.objects.filter(
            sponsor_distributor=dist,
            binary_position='RIGHT',
        ).count()
        data['sponsor_left_referrals'] = left_via_sponsor
        data['sponsor_right_referrals'] = right_via_sponsor

        return Response({'success': True, 'data': data})


class BinaryTreeStructureView(APIView):
    """
    GET /api/v1/web/binary-tree/<distributor_id>/

    Returns nested binary tree structure for visualization (max 8 levels deep).
    Use ?depth=N to control depth (max 10).
    """
    permission_classes = [IsAuthenticated]

    def get(self, request, distributor_id):
        try:
            dist = DistributorID.objects.get(pk=distributor_id, user=request.user)
        except DistributorID.DoesNotExist:
            return Response({'success': False, 'error': 'Distributor ID 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(dist.id, max_depth=depth)

        # Also return flat stats
        left_vol, right_vol = get_binary_left_right_volumes(dist.id)
        return Response({
            'success': True,
            'data': {
                'tree': tree,
                'left_volume': left_vol,
                'right_volume': right_vol,
                'subtree_total': left_vol + right_vol,
                'depth_rendered': depth,
            },
        })


class BinaryProgressView(APIView):
    """
    GET /api/v1/web/binary-progress/

    Returns binary-based level progress for all user distributor IDs.
    Suitable for displaying in the rank/progress dashboard.
    """
    permission_classes = [IsAuthenticated]

    def get(self, request):
        user = request.user
        distributors = list(
            defer_missing_product_part_payment_fields(
                DistributorID.objects.filter(user=user)
                .select_related('product__opportunity_bundle')
                .order_by('created_at'),
                relation_prefix='product',
            )
        )

        result = []
        for dist in distributors:
            try:
                snapshot = compute_binary_level_snapshot(dist)
                result.append({
                    'distributor_id': str(dist.id),
                    'distributor_code': dist.distributor_code,
                    '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
                    ),
                    'global_position': dist.global_position,
                    'subtree_total': snapshot.subtree_total if snapshot else 0,
                    'left_volume': snapshot.left_volume if snapshot else 0,
                    'right_volume': snapshot.right_volume if snapshot else 0,
                    'current_level': snapshot.current_level if snapshot else 0,
                    'last_completed_level': snapshot.last_completed_level if snapshot else 0,
                    'next_level_threshold': snapshot.next_level_required if snapshot else None,
                    'next_level': snapshot.next_level if snapshot else None,
                    'positions_to_next': snapshot.positions_to_next if snapshot else 0,
                    'progress_percent': str(snapshot.progress_percent) if snapshot else '0',
                    'calculated_at': snapshot.calculated_at.isoformat() if snapshot and snapshot.calculated_at else None,
                })
            except Exception as exc:
                result.append({
                    'distributor_id': str(dist.id),
                    'error': str(exc),
                })

        return Response({'success': True, 'data': result})
