"""
GET /api/v1/web/rewards/user-rewards/

Returns every OpportunityBundleLevel reward for the authenticated user, grouped by
opportunity bundle → distributor ID, each level carrying a computed status:

  claimed   – level reached AND a LEVEL_REWARD wallet ledger entry exists
  eligible  – level reached but no ledger entry yet (gift / service / pending)
  upcoming  – level not yet reached AND total_positions_after >= 2
  locked    – level not yet reached AND total_positions_after < 2
"""

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.rewards.services.level_service import (
    calculate_level_progress_snapshots,
    is_level_reward_coin_utilization_complete,
)
from apps.business.schemes.models import OpportunityBundleLevel
from apps.business.wallet.models import WalletLedger


# Minimum positions before non-reached levels show as "upcoming" instead of "locked"
_UNLOCK_THRESHOLD = 2


class UserRewardsView(APIView):
    """User-facing reward status per level, per distributor ID, grouped by opportunity bundle."""

    permission_classes = [IsAuthenticated]

    def get(self, request):
        user = request.user

        # ── 1. All distributor IDs for this user ─────────────────────────────
        dist_ids = list(
            DistributorID.objects.filter(user=user)
            .select_related("product__opportunity_bundle")
            .prefetch_related("level_progress")
            .order_by("created_at")
        )

        if not dist_ids:
            return Response({"success": True, "data": {"schemes": [], "first_distributor_id": None}})

        # ── 2. Collect distinct opportunity bundle IDs ───────────────────────────────────
        opportunity_bundle_ids = list({
            d.product.opportunity_bundle_id
            for d in dist_ids
            if d.product and d.product.opportunity_bundle_id
        })

        # ── 3. Fetch all OpportunityBundleLevel rows for relevant bundles ───────────────
        all_levels = list(
            OpportunityBundleLevel.objects.filter(opportunity_bundle_id__in=opportunity_bundle_ids)
            .select_related("opportunity_bundle")
            .order_by("opportunity_bundle_id", "level_number")
        )
        # Build lookup: opportunity_bundle_id → [SchemeLevel, ...]
        scheme_level_map: dict = {}
        for sl in all_levels:
            scheme_level_map.setdefault(sl.opportunity_bundle_id, []).append(sl)

        # ── 4. Fetch claimed LEVEL_REWARD ledger entries for this user ───────
        claimed_refs = set(
            WalletLedger.objects.filter(
                user=user,
                source_type="LEVEL_REWARD",
                transaction_type="CREDIT",
            ).values_list("reference_id", flat=True)
        )

        # Helper: reference_id format used in level_service.py
        def _ref(dist_id_pk, level_number):
            return f"LEVEL_REWARD_{dist_id_pk}_{level_number}"

        # ── 5. Build live level-progress lookup ──────────────────────────────
        progress_map = calculate_level_progress_snapshots(dist_ids, persist=True)

        # ── 6. Group results by opportunity bundle ───────────────────────────────────────
        scheme_groups: dict = {}

        for d in dist_ids:
            if not d.product or not d.product.opportunity_bundle_id:
                continue

            opportunity_bundle_id = str(d.product.opportunity_bundle_id)
            progress = progress_map.get(d.id, {})
            current_level = progress.get("current_level", 0)
            total_positions = progress.get("total_positions_after", 0)

            levels_for_scheme = scheme_level_map.get(d.product.opportunity_bundle_id, [])
            coin_utilization_complete = is_level_reward_coin_utilization_complete(d)

            # Build per-level reward entries for this distributor ID
            level_entries = []
            for sl in levels_for_scheme:
                ref = _ref(d.id, sl.level_number)
                is_reached = current_level >= sl.level_number
                is_claimed = ref in claimed_refs

                if is_reached and is_claimed:
                    status = "claimed"
                elif is_reached and not is_claimed:
                    status = "eligible" if coin_utilization_complete else "locked"
                elif not is_reached and total_positions >= _UNLOCK_THRESHOLD:
                    status = "upcoming"
                else:
                    status = "locked"

                level_entries.append({
                    "level_number": sl.level_number,
                    "rank_name": f"Level {sl.level_number}",  # plain fallback; Rank enrichment optional
                    "required_positions": sl.required_positions,
                    "reward_amount": str(sl.reward_amount),
                    "has_reward": sl.has_reward,
                    "has_service": sl.has_service,
                    "has_gift": sl.has_gift,
                    "gift_external": sl.gift_external or "",
                    "gift_type": sl.gift_type or "",
                    "auto_id_enabled": sl.auto_id_enabled,
                    "auto_id_count": sl.auto_id_count,
                    "status": status,
                })

            if opportunity_bundle_id not in scheme_groups:
                scheme_groups[opportunity_bundle_id] = {
                    "opportunity_bundle_id": opportunity_bundle_id,
                    "opportunity_bundle_name": d.product.opportunity_bundle.name,
                    "opportunity_bundle_id": opportunity_bundle_id,
                    "opportunity_bundle_name": d.product.opportunity_bundle.name,
                    "distributor_ids": [],
                }

            scheme_groups[opportunity_bundle_id]["distributor_ids"].append({
                "id": str(d.id),
                "code": d.distributor_code,
                "is_active": d.is_active,
                "is_auto_generated": d.is_auto_generated,
                "product_name": d.product.name if d.product else None,
                "coin_utilization_complete": coin_utilization_complete,
                "current_level": current_level,
                "total_positions": total_positions,
                "levels": level_entries,
            })

        first_dist_id = str(dist_ids[0].id) if dist_ids else None

        return Response({
            "success": True,
            "data": {
                "opportunity_bundles": list(scheme_groups.values()),
                "schemes": list(scheme_groups.values()),
                "first_distributor_id": first_dist_id,
            }
        })
