from rest_framework import viewsets, permissions, status
from rest_framework.decorators import action
from rest_framework.response import Response
from django.http import FileResponse
from django.core.mail import EmailMessage
from apps.users.permissions import CanViewFinance, IsManagement
from apps.notifications.views import create_notification
from .models import Invoice, Expense
from .serializers import InvoiceSerializer, ExpenseSerializer
from utils.pdf_utils import generate_invoice_pdf


class InvoiceViewSet(viewsets.ModelViewSet):
    permission_classes = [CanViewFinance]
    serializer_class = InvoiceSerializer
    pagination_class = None

    def get_queryset(self):
        qs = Invoice.objects.all()
        project_id = self.request.query_params.get('project')
        if project_id:
            qs = qs.filter(project_id=project_id)
        return qs

    def perform_create(self, serializer):
        """Auto-populate client info from Lead/Project if not provided."""
        data = self.request.data
        project_id = data.get('project')
        lead = None
        
        # Try to resolve client info from Project → Lead chain
        if project_id:
            from apps.projects.models import Project
            try:
                project = Project.objects.select_related('lead').get(id=project_id)
                lead = project.lead
            except Project.DoesNotExist:
                pass
        
        # Auto-fill client_name and client_email from Lead if not manually provided
        extra = {}
        if lead:
            if not data.get('client_name'):
                extra['client_name'] = lead.client_name
            if not data.get('client_email'):
                extra['client_email'] = lead.client_email or ''
            if not data.get('lead'):
                extra['lead'] = lead
        
        serializer.save(created_by=self.request.user, **extra)

    @action(detail=True, methods=['get'], permission_classes=[permissions.AllowAny])
    def download_pdf(self, request, pk=None):
        """
        Direct browser download — accepts JWT via ?token= query param.
        This allows window.open() to trigger a native file download with a proper filename.
        """
        # Authenticate via query param token if present
        from rest_framework_simplejwt.tokens import AccessToken
        from django.contrib.auth import get_user_model
        User = get_user_model()
        
        token_str = request.query_params.get('token')
        if token_str:
            try:
                token = AccessToken(token_str)
                user = User.objects.get(id=token['user_id'])
                request.user = user
            except Exception:
                return Response({'error': 'Invalid or expired token'}, status=status.HTTP_401_UNAUTHORIZED)
        
        if not request.user or not request.user.is_authenticated:
            return Response({'error': 'Authentication required'}, status=status.HTTP_401_UNAUTHORIZED)
        
        try:
            invoice = Invoice.objects.get(pk=pk)
        except Invoice.DoesNotExist:
            return Response({'error': 'Invoice not found'}, status=status.HTTP_404_NOT_FOUND)
        
        try:
            buffer = generate_invoice_pdf(invoice)
            filename = f"Invoice_{invoice.invoice_number}_{invoice.client_name.replace(' ', '_')}.pdf"
            
            response = FileResponse(buffer, content_type='application/pdf')
            response['Content-Disposition'] = f'attachment; filename="{filename}"'
            response['Access-Control-Expose-Headers'] = 'Content-Disposition'
            return response
        except Exception as e:
            return Response({'error': 'Failed to generate PDF.'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    @action(detail=True, methods=['post'], permission_classes=[IsManagement])
    def send_invoice(self, request, pk=None):
        invoice = self.get_object()
        
        # Determine recipient: use request body override, then invoice.client_email, then Lead email
        recipient = request.data.get('email') or invoice.client_email or ''
        if not recipient and invoice.lead:
            recipient = invoice.lead.client_email or ''
        
        if not recipient:
            return Response(
                {'error': 'No client email found. Please add a client email to this invoice or the linked lead.'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        try:
            buffer = generate_invoice_pdf(invoice)
        except Exception:
            return Response({'error': 'Failed to generate PDF.'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        
        email = EmailMessage(
            subject=f"Invoice {invoice.invoice_number} — {invoice.client_name} | Cyber Arsenals",
            body=(
                f"Dear {invoice.client_name},\n\n"
                f"Please find the attached professional invoice for your reference.\n\n"
                f"Invoice Number: {invoice.invoice_number}\n"
                f"Total Amount: PKR {invoice.total_amount:,.2f}\n"
                f"Balance Due: PKR {invoice.balance_due:,.2f}\n"
                f"Due Date: {invoice.due_date}\n\n"
                f"For any queries, please reply to this email or contact finance@cyberarsenals.pk.\n\n"
                f"Best Regards,\n"
                f"Cyber Arsenals Finance Department"
            ),
            from_email='finance@cyberarsenals.pk',
            to=[recipient],
            cc=['finance@cyberarsenals.pk']
        )
        email.attach(
            f"Invoice_{invoice.invoice_number}.pdf",
            buffer.getvalue(),
            'application/pdf'
        )
        
        try:
            email.send()
            invoice.status = 'Sent'
            invoice.save()
            
            # Notify finance about sent invoice
            create_notification(
                user=invoice.created_by,
                notif_type='invoice',
                title='Invoice Sent',
                message=f'Invoice {invoice.invoice_number} has been sent to {recipient}',
                link=f'/finance'
            )
            
            return Response({
                'status': 'Invoice sent successfully',
                'sent_to': recipient
            })
        except Exception as e:
            return Response({'error': f'Email delivery failed: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    @action(detail=True, methods=['post'], permission_classes=[IsManagement])
    def record_payment(self, request, pk=None):
        invoice = self.get_object()
        amount = request.data.get('amount')
        
        if not amount:
            return Response({'error': 'Payment amount is required'}, status=status.HTTP_400_BAD_REQUEST)
        
        try:
            payment_amount = float(amount)
            if payment_amount <= 0:
                raise ValueError
        except ValueError:
            return Response({'error': 'Invalid amount'}, status=status.HTTP_400_BAD_REQUEST)

        invoice.amount_paid += payment_amount
        if invoice.amount_paid >= invoice.total_amount:
            invoice.status = 'Paid'
        elif invoice.amount_paid > 0:
            invoice.status = 'Partially_Paid'
        invoice.save()
        
        # Notify about payment
        create_notification(
            user=invoice.created_by,
            notif_type='invoice',
            title='Payment Recorded',
            message=f'Payment of PKR {payment_amount:,.2f} recorded for Invoice {invoice.invoice_number}',
            link=f'/finance'
        )

        return Response(InvoiceSerializer(invoice).data)


class ExpenseViewSet(viewsets.ModelViewSet):
    permission_classes = [CanViewFinance]
    serializer_class = ExpenseSerializer
    pagination_class = None

    def get_queryset(self):
        qs = Expense.objects.all()
        project_id = self.request.query_params.get('project')
        if project_id:
            qs = qs.filter(project_id=project_id)
        return qs

    def perform_create(self, serializer):
        serializer.save(logged_by=self.request.user)
