from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from django.db.models import Q, Count, Sum, F, Avg
from django.utils import timezone
from datetime import timedelta

from .models import Transfer, TransferItem, TransferComment, TransferEvent
from .serializers import (
    TransferListSerializer, TransferDetailSerializer,
    CreateTransferSerializer, UpdateTransferSerializer,
    ApproveTransferSerializer, RejectTransferSerializer,
    ShipTransferSerializer, ReceiveTransferSerializer,
    AddCommentSerializer, CancelTransferSerializer,
    TransferCommentSerializer
)
from .permissions import TransferPermission


class TransferViewSet(viewsets.ModelViewSet):
    """ViewSet for managing transfers"""
    
    permission_classes = [IsAuthenticated, TransferPermission]
    
    def get_queryset(self):
        """Optimize queryset with related data"""
        queryset = Transfer.objects.select_related(
            'business',
            'source_location',
            'destination_location',
            'requested_by',
            'approved_by',
            'received_by',
            'rejected_by'
        ).prefetch_related(
            'items__inventory_item__brand',
            'items__inventory_item__category',
            'comments__user',
            'events__user'
        )
        
        # Filter by business
        business_id = self.request.query_params.get('business_id')
        if business_id:
            queryset = queryset.filter(business_id=business_id)
        
        # Filter by status
        status_filter = self.request.query_params.get('status')
        if status_filter:
            queryset = queryset.filter(status=status_filter)
        
        # Filter by source location
        source_location = self.request.query_params.get('source_location')
        if source_location:
            queryset = queryset.filter(source_location_id=source_location)
        
        # Filter by destination location
        destination_location = self.request.query_params.get('destination_location')
        if destination_location:
            queryset = queryset.filter(destination_location_id=destination_location)
        
        # Filter by date range
        start_date = self.request.query_params.get('start_date')
        end_date = self.request.query_params.get('end_date')
        if start_date and end_date:
            queryset = queryset.filter(
                created_at__date__gte=start_date,
                created_at__date__lte=end_date
            )
        
        # Search by transfer number
        search = self.request.query_params.get('search')
        if search:
            queryset = queryset.filter(
                Q(transfer_number__icontains=search) |
                Q(notes__icontains=search)
            )
        
        # Check user's location access
        user = self.request.user
        membership = user.business_memberships.filter(
            business_id=business_id,
            status='ACTIVE'
        ).first()
        
        if membership and not membership.can_access_all_locations:
            if membership.role.name not in ['OWNER', 'ADMIN']:
                accessible_locations = membership.accessible_locations.values_list('id', flat=True)
                queryset = queryset.filter(
                    Q(source_location_id__in=accessible_locations) |
                    Q(destination_location_id__in=accessible_locations)
                )
        
        return queryset
    
    def get_serializer_class(self):
        """Return appropriate serializer based on action"""
        if self.action == 'list':
            return TransferListSerializer
        elif self.action == 'create':
            return CreateTransferSerializer
        elif self.action in ['update', 'partial_update']:
            return UpdateTransferSerializer
        return TransferDetailSerializer
    
    def create(self, request, *args, **kwargs):
        """Create a new transfer"""
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        transfer = serializer.save()
        
        # Return detailed response
        detail_serializer = TransferDetailSerializer(transfer)
        return Response(
            detail_serializer.data,
            status=status.HTTP_201_CREATED
        )
    
    def update(self, request, *args, **kwargs):
        """Update transfer (only allowed for PENDING transfers)"""
        transfer = self.get_object()
        
        if transfer.status != 'PENDING':
            return Response(
                {'error': 'Only pending transfers can be updated'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        serializer = self.get_serializer(transfer, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        
        # Update fields
        for field, value in serializer.validated_data.items():
            setattr(transfer, field, value)
        transfer.save()
        
        detail_serializer = TransferDetailSerializer(transfer)
        return Response(detail_serializer.data)
    
    def destroy(self, request, *args, **kwargs):
        """Delete transfer (only allowed for PENDING transfers)"""
        transfer = self.get_object()
        
        if transfer.status != 'PENDING':
            return Response(
                {'error': 'Only pending transfers can be deleted'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        transfer.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)
    
    @action(detail=True, methods=['post'])
    def approve(self, request, pk=None):
        """Approve a transfer"""
        transfer = self.get_object()
        serializer = ApproveTransferSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        
        try:
            transfer.approve(
                user=request.user,
                notes=serializer.validated_data.get('notes')
            )
            detail_serializer = TransferDetailSerializer(transfer)
            return Response(detail_serializer.data)
        except PermissionError as e:
            return Response(
                {'error': str(e)},
                status=status.HTTP_403_FORBIDDEN
            )
        except Exception as e:
            return Response(
                {'error': str(e)},
                status=status.HTTP_400_BAD_REQUEST
            )
    
    @action(detail=True, methods=['post'])
    def reject(self, request, pk=None):
        """Reject a transfer"""
        transfer = self.get_object()
        serializer = RejectTransferSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        
        try:
            transfer.reject(
                user=request.user,
                reason=serializer.validated_data['reason']
            )
            detail_serializer = TransferDetailSerializer(transfer)
            return Response(detail_serializer.data)
        except PermissionError as e:
            return Response(
                {'error': str(e)},
                status=status.HTTP_403_FORBIDDEN
            )
        except Exception as e:
            return Response(
                {'error': str(e)},
                status=status.HTTP_400_BAD_REQUEST
            )
    
    @action(detail=True, methods=['post'])
    def ship(self, request, pk=None):
        """Mark transfer as shipped"""
        transfer = self.get_object()
        serializer = ShipTransferSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        
        try:
            transfer.ship(
                user=request.user,
                carrier_name=serializer.validated_data.get('carrier_name'),
                tracking_number=serializer.validated_data.get('tracking_number')
            )
            
            # Update additional shipping info
            if 'shipping_method' in serializer.validated_data:
                transfer.shipping_method = serializer.validated_data['shipping_method']
            if 'estimated_cost' in serializer.validated_data:
                transfer.estimated_cost = serializer.validated_data['estimated_cost']
            transfer.save()
            
            detail_serializer = TransferDetailSerializer(transfer)
            return Response(detail_serializer.data)
        except PermissionError as e:
            return Response(
                {'error': str(e)},
                status=status.HTTP_403_FORBIDDEN
            )
        except Exception as e:
            return Response(
                {'error': str(e)},
                status=status.HTTP_400_BAD_REQUEST
            )
    
    @action(detail=True, methods=['post'])
    def delivered(self, request, pk=None):
        """Mark transfer as delivered"""
        transfer = self.get_object()
        
        try:
            transfer.mark_delivered(user=request.user)
            detail_serializer = TransferDetailSerializer(transfer)
            return Response(detail_serializer.data)
        except ValueError as e:
            return Response(
                {'error': str(e)},
                status=status.HTTP_400_BAD_REQUEST
            )
        except Exception as e:
            return Response(
                {'error': str(e)},
                status=status.HTTP_400_BAD_REQUEST
            )
    
    @action(detail=True, methods=['post'])
    def receive(self, request, pk=None):
        """Receive transfer at destination"""
        transfer = self.get_object()
        serializer = ReceiveTransferSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        
        try:
            transfer.receive(
                user=request.user,
                items_data=serializer.validated_data['items'],
                has_discrepancies=serializer.validated_data.get('has_discrepancies', False),
                discrepancy_report=serializer.validated_data.get('discrepancy_report')
            )
            detail_serializer = TransferDetailSerializer(transfer)
            return Response(detail_serializer.data)
        except PermissionError as e:
            return Response(
                {'error': str(e)},
                status=status.HTTP_403_FORBIDDEN
            )
        except Exception as e:
            return Response(
                {'error': str(e)},
                status=status.HTTP_400_BAD_REQUEST
            )
    
    @action(detail=True, methods=['post'])
    def cancel(self, request, pk=None):
        """Cancel a transfer"""
        transfer = self.get_object()
        serializer = CancelTransferSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        
        if transfer.status not in ['PENDING', 'APPROVED']:
            return Response(
                {'error': 'Only pending or approved transfers can be cancelled'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        transfer.status = 'CANCELLED'
        transfer.notes = f"{transfer.notes}\n\nCancellation reason: {serializer.validated_data['reason']}".strip()
        transfer.save()
        
        # Create event
        TransferEvent.objects.create(
            transfer=transfer,
            event_type='CANCELLED',
            user=request.user,
            notes=serializer.validated_data['reason']
        )
        
        detail_serializer = TransferDetailSerializer(transfer)
        return Response(detail_serializer.data)
    
    @action(detail=True, methods=['post'])
    def add_comment(self, request, pk=None):
        """Add a comment to transfer"""
        transfer = self.get_object()
        serializer = AddCommentSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        
        comment = TransferComment.objects.create(
            transfer=transfer,
            user=request.user,
            text=serializer.validated_data['text'],
            is_internal=serializer.validated_data.get('is_internal', False)
        )
        
        # Create event
        TransferEvent.objects.create(
            transfer=transfer,
            event_type='COMMENT_ADDED',
            user=request.user,
            notes=f"Comment added: {serializer.validated_data['text'][:50]}..."
        )
        
        comment_serializer = TransferCommentSerializer(comment)
        return Response(comment_serializer.data, status=status.HTTP_201_CREATED)
    
    @action(detail=True, methods=['get'])
    def comments(self, request, pk=None):
        """Get all comments for a transfer"""
        transfer = self.get_object()
        comments = transfer.comments.all()
        serializer = TransferCommentSerializer(comments, many=True)
        return Response(serializer.data)
    
    @action(detail=True, methods=['get'])
    def events(self, request, pk=None):
        """Get event history for a transfer"""
        transfer = self.get_object()
        from .serializers import TransferEventSerializer
        events = transfer.events.all()
        serializer = TransferEventSerializer(events, many=True)
        return Response(serializer.data)
    
    @action(detail=False, methods=['get'])
    def stats(self, request):
        """Get transfer statistics"""
        business_id = request.query_params.get('business_id')
        if not business_id:
            return Response(
                {'error': 'business_id is required'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        # Get date range for comparison (last 30 days vs previous 30 days)
        today = timezone.now().date()
        current_period_start = today - timedelta(days=30)
        previous_period_start = today - timedelta(days=60)
        
        # Current period stats
        current_pending = Transfer.objects.filter(
            business_id=business_id,
            status='PENDING',
            created_at__date__gte=current_period_start
        ).count()
        
        current_in_transit = Transfer.objects.filter(
            business_id=business_id,
            status='IN_TRANSIT',
            created_at__date__gte=current_period_start
        ).count()
        
        current_completed = Transfer.objects.filter(
            business_id=business_id,
            status='RECEIVED',
            created_at__date__gte=current_period_start
        ).count()
        
        # Previous period stats for comparison
        previous_pending = Transfer.objects.filter(
            business_id=business_id,
            status='PENDING',
            created_at__date__gte=previous_period_start,
            created_at__date__lt=current_period_start
        ).count()
        
        previous_in_transit = Transfer.objects.filter(
            business_id=business_id,
            status='IN_TRANSIT',
            created_at__date__gte=previous_period_start,
            created_at__date__lt=current_period_start
        ).count()
        
        # Calculate percentage changes
        pending_change = self._calculate_change(previous_pending, current_pending)
        in_transit_change = self._calculate_change(previous_in_transit, current_in_transit)
        
        # Total value
        total_value = Transfer.objects.filter(
            business_id=business_id,
            created_at__date__gte=current_period_start
        ).aggregate(
            total=Sum(F('items__quantity') * F('items__inventory_item__selling_price'))
        )['total'] or 0
        
        # Average transfer time
        avg_time = Transfer.objects.filter(
            business_id=business_id,
            status='RECEIVED',
            received_date__isnull=False,
            shipped_date__isnull=False
        ).aggregate(
            avg_days=Avg(F('received_date') - F('shipped_date'))
        )['avg_days']
        
        avg_transfer_time = avg_time.days if avg_time else 0
        
        return Response({
            'pending_count': current_pending,
            'pending_change': pending_change,
            'in_transit_count': current_in_transit,
            'in_transit_change': in_transit_change,
            'completed_count': current_completed,
            'completed_period': 'Last 30 days',
            'total_value': float(total_value),
            'average_transfer_time': avg_transfer_time,
        })
    
    @action(detail=False, methods=['get'])
    def pending(self, request):
        """Get pending transfers"""
        business_id = request.query_params.get('business_id')
        if not business_id:
            return Response(
                {'error': 'business_id is required'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        transfers = self.get_queryset().filter(
            business_id=business_id,
            status='PENDING'
        )
        serializer = TransferListSerializer(transfers, many=True)
        return Response(serializer.data)
    
    @action(detail=False, methods=['get'], url_path='in-transit')
    def in_transit(self, request):
        """Get in-transit transfers"""
        business_id = request.query_params.get('business_id')
        if not business_id:
            return Response(
                {'error': 'business_id is required'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        transfers = self.get_queryset().filter(
            business_id=business_id,
            status='IN_TRANSIT'
        )
        serializer = TransferListSerializer(transfers, many=True)
        return Response(serializer.data)
    
    @action(detail=False, methods=['get'], url_path='location-summary')
    def location_summary(self, request):
        """Get transfer summary by location"""
        business_id = request.query_params.get('business_id')
        if not business_id:
            return Response(
                {'error': 'business_id is required'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        from apps.business.models import Location
        
        locations = Location.objects.filter(business_id=business_id)
        summary = []
        
        for location in locations:
            outgoing = Transfer.objects.filter(
                business_id=business_id,
                source_location=location
            )
            
            incoming = Transfer.objects.filter(
                business_id=business_id,
                destination_location=location
            )
            
            outgoing_value = outgoing.aggregate(
                total=Sum(F('items__quantity') * F('items__inventory_item__selling_price'))
            )['total'] or 0
            
            incoming_value = incoming.aggregate(
                total=Sum(F('items__quantity') * F('items__inventory_item__selling_price'))
            )['total'] or 0
            
            summary.append({
                'location_id': str(location.id),
                'location_name': location.name,
                'outgoing_count': outgoing.count(),
                'incoming_count': incoming.count(),
                'outgoing_value': float(outgoing_value),
                'incoming_value': float(incoming_value),
            })
        
        return Response({'locations': summary})
    
    def _calculate_change(self, previous, current):
        """Calculate percentage change"""
        if previous == 0:
            return 100 if current > 0 else 0
        return round(((current - previous) / previous) * 100, 2)