from django.db import models
from django.utils import timezone
from rest_framework import serializers as drf_serializers
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework import status

from apps.geo.models import (
    FranchiseStore, FranchiseAssignment, FranchisePincodeCoverage,
    FranchiseStoreInventory, FranchiseStoreEarning,
)


# ─── Helper ──────────────────────────────────────────────────────────────────

def _get_user_store(user):
    """Return the active FranchiseStore the user is assigned to, or None."""
    assignment = (
        FranchiseAssignment.objects.filter(user=user, is_active=True)
        .select_related('store')
        .first()
    )
    return assignment.store if assignment and assignment.store else None


# ─── Serializers ─────────────────────────────────────────────────────────────

class FranchiseStoreSerializer(drf_serializers.ModelSerializer):
    state_name = drf_serializers.SerializerMethodField()
    district_name = drf_serializers.SerializerMethodField()

    class Meta:
        from apps.geo.models import FranchiseStore as _M
        model = _M
        fields = [
            'id', 'code', 'name',
            'address_line1', 'address_line2',
            'contact_name', 'contact_mobile',
            'state_name', 'district_name',
        ]

    def get_state_name(self, obj):
        return obj.state.name if obj.state else None

    def get_district_name(self, obj):
        return obj.district.name if obj.district else None


class FranchiseAssignmentSerializer(drf_serializers.ModelSerializer):
    store = FranchiseStoreSerializer(read_only=True)

    class Meta:
        from apps.geo.models import FranchiseAssignment as _M
        model = _M
        fields = [
            'id', 'store', 'territory_level',
            'role_title', 'effective_from', 'effective_to',
        ]


class FranchiseInventorySerializer(drf_serializers.ModelSerializer):
    product_name = drf_serializers.SerializerMethodField()
    product_image = drf_serializers.SerializerMethodField()
    available_stock = drf_serializers.IntegerField(read_only=True)
    is_low_stock = drf_serializers.BooleanField(read_only=True)

    class Meta:
        model = FranchiseStoreInventory
        fields = [
            'id', 'product_id', 'product_name', 'product_image',
            'stock', 'reserved_stock', 'available_stock', 'is_low_stock',
            'reorder_point', 'auto_reorder', 'last_restocked',
        ]

    def get_product_name(self, obj):
        return obj.product.name if obj.product_id else None

    def get_product_image(self, obj):
        try:
            img = obj.product.images.filter(is_primary=True).first()
            req = self.context.get('request')
            if img and img.image and req:
                return req.build_absolute_uri(img.image.url)
            return None
        except Exception:
            return None


class FranchiseEarningSerializer(drf_serializers.ModelSerializer):
    order_ref = drf_serializers.SerializerMethodField()

    class Meta:
        model = FranchiseStoreEarning
        fields = [
            'id', 'order_id', 'order_ref',
            'order_amount', 'commission_percentage', 'commission_amount',
            'earning_type', 'status', 'credited_at', 'created_at',
        ]

    def get_order_ref(self, obj):
        try:
            return obj.order.reference_code
        except Exception:
            return str(obj.order_id)


class FranchisePincodeCoverageSerializer(drf_serializers.ModelSerializer):
    class Meta:
        model = FranchisePincodeCoverage
        fields = ['id', 'pincode_code', 'city', 'state', 'is_serviceable', 'assigned_date']


# ─── Views ───────────────────────────────────────────────────────────────────

class FranchiseStatusView(APIView):
    """GET: Check if authenticated user has an active franchise assignment."""
    permission_classes = [IsAuthenticated]

    def get(self, request):
        assignment = (
            FranchiseAssignment.objects.filter(user=request.user, is_active=True)
            .select_related('store', 'store__state', 'store__district')
            .first()
        )
        if not assignment:
            return Response({'is_franchise': False, 'store': None})

        return Response({
            'is_franchise': True,
            'assignment': FranchiseAssignmentSerializer(assignment).data,
        })


class FranchiseDashboardView(APIView):
    """GET: Dashboard summary — orders, earnings, inventory stats."""
    permission_classes = [IsAuthenticated]

    def get(self, request):
        store = _get_user_store(request.user)
        if not store:
            return Response({'detail': 'No active franchise assignment.'}, status=403)

        # Inventory summary
        inventory_qs = FranchiseStoreInventory.objects.filter(store=store)
        total_products = inventory_qs.count()
        low_stock_items = [i for i in inventory_qs if i.is_low_stock]

        # Earnings summary
        earnings_qs = FranchiseStoreEarning.objects.filter(store=store)
        total_earned = earnings_qs.filter(status='CREDITED').aggregate(
            total=models.Sum('commission_amount')
        )['total'] or 0
        pending_earnings = earnings_qs.filter(status='PENDING').aggregate(
            total=models.Sum('commission_amount')
        )['total'] or 0
        this_month_earned = earnings_qs.filter(
            status='CREDITED',
            credited_at__gte=timezone.now().replace(day=1, hour=0, minute=0, second=0, microsecond=0),
        ).aggregate(total=models.Sum('commission_amount'))['total'] or 0

        # Pincode coverage
        coverage_count = FranchisePincodeCoverage.objects.filter(
            store=store, is_serviceable=True
        ).count()

        # Recent orders involving this franchise (via FranchiseStoreEarning)
        recent_earnings = (
            earnings_qs
            .select_related('order')
            .order_by('-created_at')[:10]
        )

        # Low stock alerts serialized
        low_stock_data = FranchiseInventorySerializer(
            low_stock_items, many=True, context={'request': request}
        ).data

        return Response({
            'store': FranchiseStoreSerializer(store).data,
            'stats': {
                'total_products': total_products,
                'low_stock_count': len(low_stock_items),
                'total_earned': float(total_earned),
                'pending_earnings': float(pending_earnings),
                'this_month_earned': float(this_month_earned),
                'coverage_pincodes': coverage_count,
            },
            'low_stock_alerts': low_stock_data,
            'recent_earnings': FranchiseEarningSerializer(recent_earnings, many=True).data,
        })


class FranchiseInventoryView(APIView):
    """GET: Full inventory list for the franchise store."""
    permission_classes = [IsAuthenticated]

    def get(self, request):
        store = _get_user_store(request.user)
        if not store:
            return Response({'detail': 'No active franchise assignment.'}, status=403)

        inventory = (
            FranchiseStoreInventory.objects.filter(store=store)
            .select_related('product')
            .order_by('product__name')
        )
        # Filter: low_stock only
        if request.query_params.get('low_stock') == '1':
            inventory = [i for i in inventory if i.is_low_stock]

        data = FranchiseInventorySerializer(inventory, many=True, context={'request': request}).data
        return Response(data)


class FranchiseEarningsView(APIView):
    """GET: Earnings list with optional status filter."""
    permission_classes = [IsAuthenticated]

    def get(self, request):
        store = _get_user_store(request.user)
        if not store:
            return Response({'detail': 'No active franchise assignment.'}, status=403)

        qs = FranchiseStoreEarning.objects.filter(store=store).select_related('order').order_by('-created_at')

        status_filter = request.query_params.get('status')
        if status_filter and status_filter in ('PENDING', 'CREDITED', 'CANCELLED'):
            qs = qs.filter(status=status_filter)

        # Paginate: default 50
        try:
            limit = max(1, min(200, int(request.query_params.get('limit', 50))))
        except (ValueError, TypeError):
            limit = 50
        qs = qs[:limit]

        return Response(FranchiseEarningSerializer(qs, many=True).data)


class FranchisePincodesView(APIView):
    """GET: List of covered pincodes for the franchise store."""
    permission_classes = [IsAuthenticated]

    def get(self, request):
        store = _get_user_store(request.user)
        if not store:
            return Response({'detail': 'No active franchise assignment.'}, status=403)

        coverage = FranchisePincodeCoverage.objects.filter(store=store).order_by('pincode_code')
        data = FranchisePincodeCoverageSerializer(coverage, many=True).data
        return Response(data)
