"""
Vendor portal API views.

URL prefix: /api/v1/vendor/

Access control:
  - All views require IsAuthenticated + vendor ownership check.
  - Users must have an associated Vendor record.
"""

from rest_framework.views import APIView
from rest_framework.generics import ListAPIView, RetrieveUpdateAPIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework import status, serializers
from django.shortcuts import get_object_or_404
from django.db.models import Sum, Count, Q
from django.utils import timezone
from django.utils.dateparse import parse_date, parse_datetime
from datetime import timedelta
from decimal import Decimal
from django.db import transaction

from apps.business.marketplace.models_part1 import Vendor, ProductVariant, VendorContract, ContractPricing
from apps.business.marketplace.models_part2 import OrderItem, OrderShipment, OrderStatusHistory
from apps.business.products.models import Product
from apps.business.marketplace.serializers import (
    VendorDetailSerializer,
    VendorProductSerializer,
    VendorOrderItemSerializer,
    VendorAnalyticsSummarySerializer,
    OrderShipmentSerializer,
    OrderStatusHistorySerializer,
)


def get_vendor_or_404(user):
    """Get the vendor associated with the requesting user."""
    return get_object_or_404(Vendor, user=user, is_active=True)


# ---------------------------------------------------------------------------
# Vendor product creation serializer
# ---------------------------------------------------------------------------

class VendorProductCreateSerializer(serializers.ModelSerializer):
    """Serializer for vendor to create new products."""
    
    class Meta:
        model = Product
        fields = [
            'name', 'description', 'category', 'product_type',
            'base_cost', 'mrp', 'gst_percentage', 'hsn_code',
            'sku', 'slug',
            'is_active', 'vendor_managed', 'franchise_fulfilled',
        ]
    
    def validate_sku(self, value):
        if value and Product.objects.filter(sku=value).exists():
            raise serializers.ValidationError('SKU must be unique.')
        return value
    
    def validate_slug(self, value):
        if value and Product.objects.filter(slug=value).exists():
            raise serializers.ValidationError('Slug must be unique.')
        return value
    
    def validate_base_cost(self, value):
        if value <= 0:
            raise serializers.ValidationError('Base cost must be greater than 0.')
        return value
    
    def validate_mrp(self, value):
        if value and value <= 0:
            raise serializers.ValidationError('MRP must be greater than 0.')
        return value


# ---------------------------------------------------------------------------
# Vendor profile
# ---------------------------------------------------------------------------

class VendorProfileView(RetrieveUpdateAPIView):
    """GET/PATCH /vendor/profile/ — vendor profile management."""
    permission_classes = [IsAuthenticated]
    serializer_class = VendorDetailSerializer

    def get_object(self):
        return get_vendor_or_404(self.request.user)


class VendorOnboardingStatusView(APIView):
    """GET /vendor/onboarding/ — check if user has a vendor account."""
    permission_classes = [IsAuthenticated]

    def get(self, request):
        vendor = Vendor.objects.filter(user=request.user).first()
        if not vendor:
            return Response({
                'has_vendor_account': False,
                'status': None,
            })
        return Response({
            'has_vendor_account': True,
            'status': vendor.status,
            'is_active': vendor.is_active,
            'verified_at': vendor.verified_at,
            'business_name': vendor.business_name,
        })


# ---------------------------------------------------------------------------
# Vendor products
# ---------------------------------------------------------------------------

class VendorProductListView(APIView):
    """GET/POST /vendor/products/ — list vendor's products or create new product."""
    permission_classes = [IsAuthenticated]

    def get(self, request):
        """List vendor's products with status and stock info."""
        vendor = get_vendor_or_404(request.user)
        qs = Product.objects.filter(
            vendor=vendor,
        ).select_related('marketplace_category', 'brand').prefetch_related('images', 'variants')

        status_filter = request.query_params.get('status')
        if status_filter:
            qs = qs.filter(marketplace_status=status_filter.upper())

        q = request.query_params.get('q', '').strip()
        if q:
            qs = qs.filter(Q(name__icontains=q) | Q(sku__icontains=q))

        qs = qs.order_by('-created_at')
        serializer = VendorProductSerializer(qs, many=True)
        return Response(serializer.data)

    def post(self, request):
        """Create a new product for the vendor."""
        vendor = get_vendor_or_404(request.user)
        data = request.data.copy() if hasattr(request.data, 'copy') else dict(request.data)
        data['vendor'] = str(vendor.id)
        
        serializer = VendorProductCreateSerializer(data=data)
        if not serializer.is_valid():
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        
        try:
            with transaction.atomic():
                product = serializer.save(vendor=vendor)
            return Response(
                VendorProductSerializer(product).data,
                status=status.HTTP_201_CREATED
            )
        except Exception as e:
            return Response(
                {'detail': f'Failed to create product: {str(e)}'}, 
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


class VendorProductStatusUpdateView(APIView):
    """PATCH /vendor/products/<product_id>/status/ — change product status."""
    permission_classes = [IsAuthenticated]

    def patch(self, request, product_id):
        vendor = get_vendor_or_404(request.user)
        product = get_object_or_404(Product, id=product_id, vendor=vendor)
        new_status = request.data.get('marketplace_status', '').upper()
        allowed = ['DRAFT', 'ACTIVE', 'INACTIVE']
        if new_status not in allowed:
            return Response({'detail': f'Status must be one of: {allowed}'}, status=400)
        product.marketplace_status = new_status
        product.save(update_fields=['marketplace_status'])
        return Response({'id': str(product_id), 'marketplace_status': new_status})


class VendorVariantStockUpdateView(APIView):
    """PATCH /vendor/variants/<variant_id>/stock/ — update variant stock."""
    permission_classes = [IsAuthenticated]

    def patch(self, request, variant_id):
        vendor = get_vendor_or_404(request.user)
        variant = get_object_or_404(ProductVariant, id=variant_id, product__vendor=vendor)
        stock = request.data.get('stock')
        if stock is None or int(stock) < 0:
            return Response({'detail': 'Valid stock value required.'}, status=400)
        variant.stock = int(stock)
        variant.save(update_fields=['stock'])
        return Response({'id': str(variant_id), 'stock': variant.stock})


# ---------------------------------------------------------------------------
# Vendor orders
# ---------------------------------------------------------------------------

class VendorOrderListView(ListAPIView):
    """GET /vendor/orders/ — orders fulfilled by this vendor."""
    permission_classes = [IsAuthenticated]
    serializer_class = VendorOrderItemSerializer

    def get_queryset(self):
        vendor = get_vendor_or_404(self.request.user)
        qs = OrderItem.objects.filter(
            vendor=vendor,
        ).select_related('order', 'product').order_by('-created_at')

        status_filter = self.request.query_params.get('status')
        if status_filter:
            qs = qs.filter(status=status_filter.upper())

        return qs


class VendorOrderStatusUpdateView(APIView):
    """PATCH /vendor/orders/<order_item_id>/status/ — update fulfillment status."""
    permission_classes = [IsAuthenticated]

    VALID_TRANSITIONS = {
        'CONFIRMED': ['PACKED'],
        'PACKED': ['SHIPPED'],
        'SHIPPED': ['DELIVERED'],
    }

    def patch(self, request, order_item_id):
        vendor = get_vendor_or_404(request.user)
        item = get_object_or_404(OrderItem, id=order_item_id, vendor=vendor)
        new_status = request.data.get('status', '').upper()

        allowed_next = self.VALID_TRANSITIONS.get(item.status, [])
        if new_status not in allowed_next:
            return Response({
                'detail': f"Cannot transition from '{item.status}' to '{new_status}'. "
                          f"Allowed: {allowed_next}"
            }, status=400)

        item.status = new_status
        item.save(update_fields=['status'])

        OrderStatusHistory.objects.create(
            order=item.order,
            status=new_status,
            description=f"Vendor updated to {new_status}",
            recorded_by='VENDOR',
        )

        shipment_map = {
            'PACKED': 'PENDING',
            'SHIPPED': 'IN_TRANSIT',
            'DELIVERED': 'DELIVERED',
        }
        shipment = OrderShipment.objects.filter(order=item.order).first()
        if shipment and new_status in shipment_map:
            shipment.status = shipment_map[new_status]
            if new_status == 'SHIPPED' and not shipment.picked_up_at:
                shipment.picked_up_at = timezone.now()
            if new_status == 'DELIVERED':
                shipment.delivered_at = timezone.now()
            shipment.save(update_fields=['status', 'picked_up_at', 'delivered_at', 'last_update'])

        return Response({
            'id': str(order_item_id),
            'status': new_status,
            'order_reference': item.order.reference_id,
        })


# ---------------------------------------------------------------------------
# Vendor analytics
# ---------------------------------------------------------------------------

class VendorAnalyticsView(APIView):
    """GET /vendor/analytics/ — vendor sales analytics summary."""
    permission_classes = [IsAuthenticated]

    def get(self, request):
        vendor = get_vendor_or_404(request.user)
        period = request.query_params.get('period', '30d')

        now = timezone.now()
        days = {'7d': 7, '30d': 30, '90d': 90, '365d': 365}.get(period, 30)
        since = now - timedelta(days=days)

        all_items = OrderItem.objects.filter(vendor=vendor)
        period_items = all_items.filter(created_at__gte=since)

        total_orders = all_items.count()
        total_revenue = all_items.aggregate(total=Sum('total_price'))['total'] or Decimal('0.00')
        pending = all_items.filter(status__in=['PENDING', 'CONFIRMED', 'PACKED']).count()
        completed = all_items.filter(status='DELIVERED').count()

        # Top products
        top_products = (
            period_items
            .values('product__id', 'product__name', 'product__sku')
            .annotate(orders=Count('id'), revenue=Sum('total_price'))
            .order_by('-revenue')[:5]
        )

        # Low stock products
        low_stock = ProductVariant.objects.filter(
            product__vendor=vendor, is_active=True, stock__lte=10
        ).select_related('product').values(
            'product__name', 'sku', 'name', 'stock'
        )[:10]

        # Monthly revenue (last 6 months)
        from django.db.models.functions import TruncMonth
        monthly = (
            all_items
            .filter(created_at__gte=now - timedelta(days=180))
            .annotate(month=TruncMonth('created_at'))
            .values('month')
            .annotate(revenue=Sum('total_price'), orders=Count('id'))
            .order_by('month')
        )

        return Response({
            'period': period,
            'total_orders': total_orders,
            'total_revenue': str(total_revenue),
            'pending_orders': pending,
            'completed_orders': completed,
            'top_products': list(top_products),
            'low_stock_products': list(low_stock),
            'monthly_revenue': [
                {
                    'month': m['month'].strftime('%b %Y') if m['month'] else '',
                    'revenue': str(m['revenue'] or 0),
                    'orders': m['orders'],
                }
                for m in monthly
            ],
        })


# ---------------------------------------------------------------------------
# Vendor commercials: contracts, pricing maps, and product controls
# ---------------------------------------------------------------------------

class VendorContractListCreateView(APIView):
    """GET/POST /vendor/contracts/ — vendor agreements with the company."""
    permission_classes = [IsAuthenticated]

    def get(self, request):
        vendor = get_vendor_or_404(request.user)
        contracts = VendorContract.objects.filter(vendor=vendor).order_by('-created_at')
        rows = [
            {
                'id': str(c.id),
                'contract_number': c.contract_number,
                'start_date': c.start_date,
                'end_date': c.end_date,
                'base_commission_percentage': str(c.base_commission_percentage),
                'is_active': c.is_active,
                'created_at': c.created_at,
                'pricing_rules_count': c.pricing_rules.count(),
            }
            for c in contracts
        ]
        return Response(rows)

    def post(self, request):
        return Response(
            {'detail': 'Contracts are admin-controlled. Please contact admin to create or modify agreements.'},
            status=status.HTTP_403_FORBIDDEN,
        )


class VendorContractDetailView(APIView):
    """PATCH /vendor/contracts/<contract_id>/ — update contract state."""
    permission_classes = [IsAuthenticated]

    def patch(self, request, contract_id):
        return Response(
            {'detail': 'Contract updates are admin-controlled.'},
            status=status.HTTP_403_FORBIDDEN,
        )


class VendorContractPricingListCreateView(APIView):
    """GET/POST /vendor/price-mappings/ — product-level buy/sell/margin rules."""
    permission_classes = [IsAuthenticated]

    def get(self, request):
        vendor = get_vendor_or_404(request.user)
        contract_id = request.query_params.get('contract_id')
        qs = ContractPricing.objects.filter(contract__vendor=vendor).select_related('product', 'contract', 'franchise_store')
        if contract_id:
            qs = qs.filter(contract_id=contract_id)
        qs = qs.order_by('-valid_from')

        rows = []
        now = timezone.now()
        for rule in qs:
            company_margin = rule.sell_price - rule.buy_price
            rows.append({
                'id': str(rule.id),
                'contract_id': str(rule.contract_id),
                'contract_number': rule.contract.contract_number,
                'product_id': str(rule.product_id),
                'product_name': rule.product.name,
                'pricing_tier': rule.pricing_tier,
                'pincode': rule.pincode,
                'franchise_store_id': str(rule.franchise_store_id) if rule.franchise_store_id else None,
                'franchise_store_name': getattr(rule.franchise_store, 'store_name', None) if rule.franchise_store else None,
                'buy_price': str(rule.buy_price),
                'sell_price': str(rule.sell_price),
                'margin_percentage': str(rule.margin_percentage),
                'company_margin_per_unit': str(company_margin),
                'valid_from': rule.valid_from,
                'valid_until': rule.valid_until,
                'is_current': rule.valid_from <= now <= rule.valid_until,
                'delivery_owner_options': ['VENDOR_FULFILLED', 'COMPANY_FULFILLED', 'FRANCHISE_FULFILLED'],
            })
        return Response(rows)

    def post(self, request):
        return Response(
            {'detail': 'Pricing mappings are admin-controlled. Please contact admin for changes.'},
            status=status.HTTP_403_FORBIDDEN,
        )


class VendorProductCommercialUpdateView(APIView):
    """PATCH /vendor/products/<product_id>/commercials/ — costs, margin basis, fulfillment ownership."""
    permission_classes = [IsAuthenticated]

    def patch(self, request, product_id):
        vendor = get_vendor_or_404(request.user)
        product = get_object_or_404(Product, id=product_id, vendor=vendor)

        allowed_fields = {
            'base_cost',
            'mrp',
            'is_active',
            'marketplace_status',
            'vendor_managed',
            'franchise_fulfilled',
        }
        updates = []

        for field in allowed_fields:
            if field in request.data:
                setattr(product, field, request.data.get(field))
                updates.append(field)

        if 'marketplace_status' in request.data:
            status_value = str(request.data.get('marketplace_status', '')).upper()
            allowed_status = {'DRAFT', 'PENDING_APPROVAL', 'ACTIVE', 'INACTIVE', 'DISCONTINUED'}
            if status_value not in allowed_status:
                return Response({'detail': f'marketplace_status must be one of {sorted(list(allowed_status))}.'}, status=400)
            product.marketplace_status = status_value

        if updates:
            product.save(update_fields=list(set(updates)))

        return Response({
            'id': str(product.id),
            'base_cost': str(product.base_cost),
            'mrp': str(product.mrp or 0),
            'marketplace_status': product.marketplace_status,
            'is_active': product.is_active,
            'vendor_managed': product.vendor_managed,
            'franchise_fulfilled': product.franchise_fulfilled,
            'delivery_owner_summary': {
                'vendor': bool(product.vendor_managed),
                'company': True,
                'franchise_if_available': bool(product.franchise_fulfilled),
            },
        })
