from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from crm.models import Quote, Invoice, Lead, InvoiceItem, ItemTemplate
from crm.serializers import QuoteSerializer, InvoiceSerializer
from crm.models import Payment
from crm.serializers.quote import PaymentSerializer, ItemTemplateSerializer

from rest_framework import mixins

class QuoteViewSet(viewsets.ModelViewSet):
    queryset = Quote.objects.all().prefetch_related('items')
    serializer_class = QuoteSerializer

    def create(self, request, *args, **kwargs):
        is_many = isinstance(request.data, list)
        serializer = self.get_serializer(data=request.data, many=is_many)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    @action(detail=True, methods=['post'])
    def convert_to_invoice(self, request, pk=None):
        quote = self.get_object()
        from crm.models import Invoice

        # Check if invoice already exists for this quote
        existing_invoice = Invoice.objects.filter(quote=quote).first()
        
        if existing_invoice:
            # Invoice already exists, ensure it has items from the quote
            existing_invoice.ensure_items_from_quote()
            serializer = InvoiceSerializer(existing_invoice)
            lead_data = quote.get_lead_data() if hasattr(quote, 'get_lead_data') else {}
            response_data = serializer.data
            response_data['lead'] = lead_data
            return Response({
                'detail': 'Invoice already exists and has been updated with quote items.',
                'invoice': response_data
            }, status=status.HTTP_200_OK)
        else:
            # No invoice exists, create one directly without relying on signals
            # This prevents potential database lock issues
            try:
                invoice = quote.convert_to_invoice()
                
                # Mark quote as converted
                quote.is_invoice_converted = True
                quote.save(update_fields=['is_invoice_converted'])
                
                if invoice:
                    serializer = InvoiceSerializer(invoice)
                    lead_data = quote.get_lead_data() if hasattr(quote, 'get_lead_data') else {}
                    response_data = serializer.data
                    response_data['lead'] = lead_data
                    return Response({
                        'detail': 'Invoice created successfully.',
                        'invoice': response_data
                    }, status=status.HTTP_201_CREATED)
                else:
                    return Response({'detail': 'Failed to create invoice.'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            except Exception as e:
                return Response({
                    'detail': f'Error creating invoice: {str(e)}'
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    @action(detail=True, methods=['get'])
    def get_invoice(self, request, pk=None):
        quote = self.get_object()
        from crm.models import Invoice
        invoice = Invoice.objects.filter(quote=quote).first()
        if invoice:
            invoice.ensure_items_from_quote()
            serializer = InvoiceSerializer(invoice)
            lead_data = quote.get_lead_data() if hasattr(quote, 'get_lead_data') else {}
            response_data = serializer.data
            response_data['lead'] = lead_data
            return Response(response_data, status=status.HTTP_200_OK)
        else:
            return Response({'detail': 'No invoice found for this quote.'}, status=status.HTTP_404_NOT_FOUND)


class InvoiceViewSet(viewsets.ModelViewSet):
    queryset = Invoice.objects.all().prefetch_related('items')
    serializer_class = InvoiceSerializer

    def create(self, request, *args, **kwargs):
        from lib.sevices import generate_invoice_number
        from datetime import date
        
        data = request.data

        # Extract fields from request
        lead_id = data.get("lead")
        quote_id = data.get("quote")
        items_data = data.get("items", [])
        currency = data.get("currency", "INR").upper()
        invoice_date = data.get("invoice_date", date.today())

        # Get lead and quote objects
        try:
            lead = Lead.objects.get(id=lead_id)
        except Lead.DoesNotExist:
            return Response({"error": "Lead not found"}, status=status.HTTP_400_BAD_REQUEST)

        quote = None
        if quote_id:
            quote = Quote.objects.filter(id=quote_id).first()

        # Step 1: Create invoice with auto-generated invoice number
        invoice = Invoice.objects.create(
            lead=lead,
            quote=quote,
            invoice_number=generate_invoice_number(),
            invoice_date=invoice_date,
            office=quote.office if quote else None,  # Copy office from quote if available
            currency=currency,
        )

        # Step 2: Add invoice items
        for item in items_data:
            InvoiceItem.objects.create(
                invoice=invoice,
                item_name=item["item_name"],
                description=item.get("description", ""),
                qty=item["qty"],
                rate=item["rate"],
                amount=item["amount"],
            )

        # Step 3: Refresh invoice to load related items
        invoice.refresh_from_db()

        # Step 4: Generate PDF
        invoice.generate_pdf()

        # Step 5: Serialize and return
        serializer = self.get_serializer(invoice)
        return Response(serializer.data, status=status.HTTP_201_CREATED)


class ItemTemplateViewSet(viewsets.ModelViewSet):
    queryset = ItemTemplate.objects.filter(is_active=True)
    serializer_class = ItemTemplateSerializer

    def get_queryset(self):
        queryset = super().get_queryset()
        search = self.request.query_params.get('search', None)
        if search:
            queryset = queryset.filter(name__icontains=search)
        return queryset


class PaymentViewSet(viewsets.ModelViewSet):
    queryset = Payment.objects.all()
    serializer_class = PaymentSerializer

    def get_queryset(self):
        queryset = super().get_queryset()
        invoice_id = self.request.query_params.get('invoice')
        if invoice_id:
            queryset = queryset.filter(invoice_id=invoice_id)
        return queryset

    def create(self, request, *args, **kwargs):
        # Prevent duplicate payment creation on refresh by checking for idempotency
        data = request.data
        invoice_id = data.get("invoice")
        amount = data.get("amount")
        payment_date = data.get("payment_date")
        transaction_id = data.get("transaction_id")

        # You can define your own idempotency logic here. For example:
        # If a payment with same invoice, amount, payment_date, and transaction_id exists, return it.
        existing_payment = Payment.objects.filter(
            invoice_id=invoice_id,
            amount=amount,
            payment_date=payment_date,
            transaction_id=transaction_id
        ).first()
        if existing_payment:
            serializer = self.get_serializer(existing_payment)
            return Response(serializer.data, status=status.HTTP_200_OK)

        return super().create(request, *args, **kwargs)

