"""
DRF API views for billing endpoints.
"""

from django.db import transaction
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from smoothschedule.billing.api.serializers import AddOnProductSerializer
from smoothschedule.billing.api.serializers import InvoiceListSerializer
from smoothschedule.billing.api.serializers import InvoiceSerializer
from smoothschedule.billing.api.serializers import PlanVersionSerializer
from smoothschedule.billing.api.serializers import SubscriptionSerializer
from smoothschedule.billing.api.serializers import (
    FeatureSerializer,
    FeatureCreateSerializer,
    PlanSerializer,
    PlanCreateSerializer,
    PlanWithVersionsSerializer,
    PlanVersionCreateSerializer,
    PlanVersionUpdateSerializer,
    PlanVersionDetailSerializer,
    AddOnProductCreateSerializer,
    PlanFeatureWriteSerializer,
)
from smoothschedule.billing.models import (
    AddOnProduct,
    Feature,
    Invoice,
    Plan,
    PlanFeature,
    PlanVersion,
    Subscription,
)
from smoothschedule.billing.services.entitlements import EntitlementService
from smoothschedule.platform.admin.permissions import IsPlatformAdmin


class EntitlementsView(APIView):
    """
    GET /api/me/entitlements/

    Returns the current business's effective entitlements.
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        tenant = getattr(request.user, "tenant", None)
        if not tenant:
            return Response({})

        entitlements = EntitlementService.get_effective_entitlements(tenant)
        return Response(entitlements)


class CurrentSubscriptionView(APIView):
    """
    GET /api/me/subscription/

    Returns the current business's subscription with plan version details.
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        tenant = getattr(request.user, "tenant", None)
        if not tenant:
            return Response(
                {"detail": "No tenant context"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        subscription = getattr(tenant, "billing_subscription", None)
        if not subscription:
            return Response(
                {"detail": "No subscription found"},
                status=status.HTTP_404_NOT_FOUND,
            )

        serializer = SubscriptionSerializer(subscription)
        return Response(serializer.data)


class PlanCatalogView(APIView):
    """
    GET /api/billing/plans/

    Returns public, non-legacy plan versions (the plan catalog).
    """

    # This endpoint is public - no authentication required
    # Allows visitors to see pricing before signup
    permission_classes = [AllowAny]

    def get(self, request):
        # Filter for public, non-legacy plans
        plan_versions = (
            PlanVersion.objects.filter(is_public=True, is_legacy=False)
            .select_related("plan")
            .prefetch_related("features__feature")
            .order_by("plan__display_order", "plan__name", "-version")
        )

        # Filter by availability window (is_available property)
        available_versions = [pv for pv in plan_versions if pv.is_available]

        serializer = PlanVersionSerializer(available_versions, many=True)
        return Response(serializer.data)


class AddOnCatalogView(APIView):
    """
    GET /api/billing/addons/

    Returns available add-on products.
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        addons = AddOnProduct.objects.filter(is_active=True)
        serializer = AddOnProductSerializer(addons, many=True)
        return Response(serializer.data)


class InvoiceListView(APIView):
    """
    GET /api/billing/invoices/

    Returns paginated invoice list for the current business.
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        tenant = getattr(request.user, "tenant", None)
        if not tenant:
            return Response(
                {"detail": "No tenant context"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Tenant-isolated query
        invoices = Invoice.objects.filter(business=tenant).order_by("-created_at")

        # Simple pagination
        page_size = int(request.query_params.get("page_size", 20))
        page = int(request.query_params.get("page", 1))
        offset = (page - 1) * page_size

        total_count = invoices.count()
        invoices_page = invoices[offset : offset + page_size]

        serializer = InvoiceListSerializer(invoices_page, many=True)
        return Response(
            {
                "count": total_count,
                "page": page,
                "page_size": page_size,
                "results": serializer.data,
            }
        )


class InvoiceDetailView(APIView):
    """
    GET /api/billing/invoices/{id}/

    Returns invoice detail with line items.
    """

    permission_classes = [IsAuthenticated]

    def get(self, request, invoice_id):
        tenant = getattr(request.user, "tenant", None)
        if not tenant:
            return Response(
                {"detail": "No tenant context"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Tenant-isolated query - cannot see other tenant's invoices
        try:
            invoice = Invoice.objects.prefetch_related("lines").get(
                business=tenant, id=invoice_id
            )
        except Invoice.DoesNotExist:
            return Response(
                {"detail": "Invoice not found"},
                status=status.HTTP_404_NOT_FOUND,
            )

        serializer = InvoiceSerializer(invoice)
        return Response(serializer.data)


# =============================================================================
# Admin ViewSets (for platform admin management)
# =============================================================================


class FeatureViewSet(viewsets.ModelViewSet):
    """
    ViewSet for managing Features.
    Platform admins only.

    Features are the building blocks that can be assigned to plans.
    """

    queryset = Feature.objects.all().order_by("name")
    permission_classes = [IsAuthenticated, IsPlatformAdmin]

    def get_serializer_class(self):
        if self.action in ["create", "update", "partial_update"]:
            return FeatureCreateSerializer
        return FeatureSerializer


class PlanViewSet(viewsets.ModelViewSet):
    """
    ViewSet for managing Plans.
    Platform admins only.

    Plans are logical groupings (Free, Starter, Pro, Enterprise).
    Each plan can have multiple versions for grandfathering.
    """

    queryset = Plan.objects.all().prefetch_related(
        "versions", "versions__features", "versions__features__feature"
    ).order_by("display_order", "name")
    permission_classes = [IsAuthenticated, IsPlatformAdmin]

    def get_serializer_class(self):
        if self.action in ["create", "update", "partial_update"]:
            return PlanCreateSerializer
        if self.action == "retrieve":
            return PlanWithVersionsSerializer
        return PlanSerializer

    def list(self, request, *args, **kwargs):
        """List all plans with their active versions."""
        queryset = self.get_queryset()
        serializer = PlanWithVersionsSerializer(queryset, many=True)
        return Response(serializer.data)

    @action(detail=True, methods=["post"])
    def create_version(self, request, pk=None):
        """
        Create a new version for this plan.
        POST /api/billing/admin/plans/{id}/create_version/
        """
        plan = self.get_object()
        serializer = PlanVersionCreateSerializer(
            data={**request.data, "plan_code": plan.code}
        )
        serializer.is_valid(raise_exception=True)
        version = serializer.save()
        return Response(
            PlanVersionDetailSerializer(version).data,
            status=status.HTTP_201_CREATED,
        )


class PlanVersionViewSet(viewsets.ModelViewSet):
    """
    ViewSet for managing PlanVersions.
    Platform admins only.

    Key behavior:
    - When updating a version with active subscribers, a new version is
      created and the old one is marked as legacy (grandfathering).
    - Versions without subscribers can be edited directly.
    """

    queryset = PlanVersion.objects.all().select_related("plan").prefetch_related(
        "features", "features__feature"
    ).order_by("plan__display_order", "plan__name", "-version")
    permission_classes = [IsAuthenticated, IsPlatformAdmin]

    def get_serializer_class(self):
        if self.action == "create":
            return PlanVersionCreateSerializer
        if self.action in ["update", "partial_update"]:
            return PlanVersionUpdateSerializer
        return PlanVersionDetailSerializer

    def update(self, request, *args, **kwargs):
        """
        Update a plan version with grandfathering support.

        If the version has active subscribers:
        1. Mark the current version as legacy
        2. Create a new version with the updates
        3. Return the new version

        If no active subscribers:
        - Update the version directly
        """
        instance = self.get_object()
        partial = kwargs.pop("partial", False)

        # Check for active subscribers
        subscriber_count = Subscription.objects.filter(
            plan_version=instance,
            status__in=["active", "trial"],
        ).count()

        if subscriber_count > 0:
            # Grandfathering: create new version, mark old as legacy
            return self._create_new_version(instance, request.data)

        # No subscribers - update directly
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        # Handle features if provided
        features_data = request.data.get("features")
        if features_data is not None:
            self._update_features(instance, features_data)

        return Response(PlanVersionDetailSerializer(instance).data)

    def _create_new_version(self, old_version, data):
        """Create a new version based on the old one with updates.

        Note: Features/permissions/limits are managed via PlanFeature M2M.
        They are copied from the old version or provided in the 'features' array.
        """
        with transaction.atomic():
            # Mark old version as legacy
            old_version.is_legacy = True
            old_version.is_public = False
            old_version.save()

            # Determine new version number
            next_version = old_version.plan.versions.count() + 1

            # Create new version with all fields
            new_version = PlanVersion.objects.create(
                plan=old_version.plan,
                version=next_version,
                name=data.get("name", old_version.name),
                is_public=data.get("is_public", True),
                is_legacy=False,
                starts_at=data.get("starts_at"),
                ends_at=data.get("ends_at"),
                # Pricing
                price_monthly_cents=data.get("price_monthly_cents", old_version.price_monthly_cents),
                price_yearly_cents=data.get("price_yearly_cents", old_version.price_yearly_cents),
                # Transaction fees
                transaction_fee_percent=data.get("transaction_fee_percent", old_version.transaction_fee_percent),
                transaction_fee_fixed_cents=data.get("transaction_fee_fixed_cents", old_version.transaction_fee_fixed_cents),
                # Trial
                trial_days=data.get("trial_days", old_version.trial_days),
                # Communication pricing (costs when feature is enabled)
                sms_price_per_message_cents=data.get("sms_price_per_message_cents", old_version.sms_price_per_message_cents),
                masked_calling_price_per_minute_cents=data.get("masked_calling_price_per_minute_cents", old_version.masked_calling_price_per_minute_cents),
                proxy_number_monthly_fee_cents=data.get("proxy_number_monthly_fee_cents", old_version.proxy_number_monthly_fee_cents),
                # Credit settings
                default_auto_reload_enabled=data.get("default_auto_reload_enabled", old_version.default_auto_reload_enabled),
                default_auto_reload_threshold_cents=data.get("default_auto_reload_threshold_cents", old_version.default_auto_reload_threshold_cents),
                default_auto_reload_amount_cents=data.get("default_auto_reload_amount_cents", old_version.default_auto_reload_amount_cents),
                # Display settings
                is_most_popular=data.get("is_most_popular", old_version.is_most_popular),
                show_price=data.get("show_price", old_version.show_price),
                marketing_features=data.get("marketing_features", old_version.marketing_features),
                # Stripe
                stripe_product_id=data.get("stripe_product_id", old_version.stripe_product_id),
                stripe_price_id_monthly=data.get("stripe_price_id_monthly", old_version.stripe_price_id_monthly),
                stripe_price_id_yearly=data.get("stripe_price_id_yearly", old_version.stripe_price_id_yearly),
            )

            # Copy features from old version or use provided features
            features_data = data.get("features")
            if features_data is not None:
                self._create_features(new_version, features_data)
            else:
                # Copy features from old version
                for old_feature in old_version.features.all():
                    PlanFeature.objects.create(
                        plan_version=new_version,
                        feature=old_feature.feature,
                        bool_value=old_feature.bool_value,
                        int_value=old_feature.int_value,
                    )

        return Response(
            {
                "message": f"Created new version (v{next_version}) and marked v{old_version.version} as legacy. {Subscription.objects.filter(plan_version=old_version, status__in=['active', 'trial']).count()} subscriber(s) will keep their current plan.",
                "old_version": PlanVersionDetailSerializer(old_version).data,
                "new_version": PlanVersionDetailSerializer(new_version).data,
            },
            status=status.HTTP_201_CREATED,
        )

    def _update_features(self, version, features_data):
        """Update features for a version."""
        # Clear existing features
        version.features.all().delete()
        self._create_features(version, features_data)

    def _create_features(self, version, features_data):
        """Create features for a version."""
        for feature_data in features_data:
            try:
                feature = Feature.objects.get(code=feature_data["feature_code"])
            except Feature.DoesNotExist:
                continue

            PlanFeature.objects.create(
                plan_version=version,
                feature=feature,
                bool_value=feature_data.get("bool_value"),
                int_value=feature_data.get("int_value"),
            )

    @action(detail=True, methods=["post"])
    def mark_legacy(self, request, pk=None):
        """
        Mark a version as legacy (hidden from new signups).
        POST /api/billing/admin/plan-versions/{id}/mark_legacy/
        """
        version = self.get_object()
        version.is_legacy = True
        version.is_public = False
        version.save()
        return Response(PlanVersionDetailSerializer(version).data)

    @action(detail=True, methods=["get"])
    def subscribers(self, request, pk=None):
        """
        Get list of subscribers on this version.
        GET /api/billing/admin/plan-versions/{id}/subscribers/
        """
        version = self.get_object()
        subscriptions = Subscription.objects.filter(
            plan_version=version
        ).select_related("business")

        return Response({
            "version": version.name,
            "subscriber_count": subscriptions.count(),
            "subscribers": [
                {
                    "business_id": sub.business.id,
                    "business_name": sub.business.name,
                    "status": sub.status,
                    "started_at": sub.started_at,
                }
                for sub in subscriptions[:100]  # Limit to 100
            ],
        })

    @action(detail=True, methods=["post"])
    def force_update(self, request, pk=None):
        """
        DANGEROUS: Force update a plan version in place, affecting all subscribers.

        This bypasses grandfathering and modifies the plan for ALL existing subscribers.
        Only superusers can perform this action.

        POST /api/billing/admin/plan-versions/{id}/force_update/

        Requires confirmation via `confirm: true` in request body.
        """
        # Only superusers can force update
        if not request.user.is_superuser:
            return Response(
                {"detail": "Only superusers can force update plan versions."},
                status=status.HTTP_403_FORBIDDEN,
            )

        version = self.get_object()

        # Require explicit confirmation
        if not request.data.get("confirm"):
            # Get affected subscriber count
            subscriber_count = Subscription.objects.filter(
                plan_version=version,
                status__in=["active", "trial"],
            ).count()

            return Response(
                {
                    "detail": "Force update requires explicit confirmation.",
                    "warning": f"This will modify the plan for {subscriber_count} active subscriber(s). "
                               "Changes to pricing, features, and limits will immediately affect all existing customers. "
                               "This action cannot be undone.",
                    "subscriber_count": subscriber_count,
                    "requires_confirm": True,
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Get affected subscribers before update for audit log
        affected_subscriptions = list(
            Subscription.objects.filter(
                plan_version=version,
                status__in=["active", "trial"],
            ).select_related("business").values_list("business__name", flat=True)[:100]
        )
        affected_count = Subscription.objects.filter(
            plan_version=version,
            status__in=["active", "trial"],
        ).count()

        # Perform the update in place (no grandfathering)
        with transaction.atomic():
            serializer = self.get_serializer(version, data=request.data, partial=True)
            serializer.is_valid(raise_exception=True)
            serializer.save()

            # Handle features if provided
            features_data = request.data.get("features")
            if features_data is not None:
                self._update_features(version, features_data)

            # Refresh from DB
            version.refresh_from_db()

        return Response({
            "message": f"Force updated plan version. {affected_count} subscriber(s) affected.",
            "version": PlanVersionDetailSerializer(version).data,
            "affected_count": affected_count,
            "affected_businesses": list(affected_subscriptions),
        })


class AddOnProductViewSet(viewsets.ModelViewSet):
    """
    ViewSet for managing AddOnProducts.
    Platform admins only.
    """

    queryset = AddOnProduct.objects.all().order_by("name")
    permission_classes = [IsAuthenticated, IsPlatformAdmin]

    def get_serializer_class(self):
        if self.action in ["create", "update", "partial_update"]:
            return AddOnProductCreateSerializer
        return AddOnProductSerializer
