"""
Invoice Service - Handles invoice creation, management, and PDF generation
"""
from decimal import Decimal
from datetime import datetime, timedelta
from typing import Dict, List, Optional
from django.db import transaction
from django.utils import timezone

from ..models import Invoice, CreditPackage
from ....auth.models import Account, Subscription


class InvoiceService:
    """Service for managing invoices"""
    
    @staticmethod
    def generate_invoice_number(account: Account) -> str:
        """
        Generate unique invoice number
        Format: INV-{ACCOUNT_ID}-{YEAR}{MONTH}-{COUNTER}
        """
        now = timezone.now()
        prefix = f"INV-{account.id}-{now.year}{now.month:02d}"
        
        # Get count of invoices for this account this month
        count = Invoice.objects.filter(
            account=account,
            created_at__year=now.year,
            created_at__month=now.month
        ).count()
        
        return f"{prefix}-{count + 1:04d}"
    
    @staticmethod
    @transaction.atomic
    def create_subscription_invoice(
        subscription: Subscription,
        billing_period_start: datetime,
        billing_period_end: datetime
    ) -> Invoice:
        """
        Create invoice for subscription billing period
        """
        account = subscription.account
        plan = subscription.plan
        
        invoice = Invoice.objects.create(
            account=account,
            subscription=subscription,
            invoice_number=InvoiceService.generate_invoice_number(account),
            billing_email=account.billing_email or account.users.filter(role='owner').first().email,
            status='pending',
            currency='USD',
            invoice_date=timezone.now().date(),
            due_date=billing_period_end.date(),
            billing_period_start=billing_period_start,
            billing_period_end=billing_period_end
        )
        
        # Add line item for subscription
        invoice.add_line_item(
            description=f"{plan.name} Plan - {billing_period_start.strftime('%b %Y')}",
            quantity=1,
            unit_price=plan.price,
            amount=plan.price
        )
        
        invoice.calculate_totals()
        invoice.save()
        
        return invoice
    
    @staticmethod
    @transaction.atomic
    def create_credit_package_invoice(
        account: Account,
        credit_package: CreditPackage
    ) -> Invoice:
        """
        Create invoice for credit package purchase
        """
        invoice = Invoice.objects.create(
            account=account,
            invoice_number=InvoiceService.generate_invoice_number(account),
            billing_email=account.billing_email or account.users.filter(role='owner').first().email,
            status='pending',
            currency='USD',
            invoice_date=timezone.now().date(),
            due_date=timezone.now().date(),
            metadata={
                'credit_package_id': credit_package.id,
                'credit_amount': credit_package.credits,
            },
        )
        
        # Add line item for credit package
        invoice.add_line_item(
            description=f"{credit_package.name} - {credit_package.credits:,} Credits",
            quantity=1,
            unit_price=credit_package.price,
            amount=credit_package.price
        )
        
        invoice.calculate_totals()
        invoice.save()
        
        return invoice
    
    @staticmethod
    @transaction.atomic
    def create_custom_invoice(
        account: Account,
        line_items: List[Dict],
        billing_email: Optional[str] = None,
        notes: Optional[str] = None,
        due_date: Optional[datetime] = None
    ) -> Invoice:
        """
        Create custom invoice with multiple line items
        
        Args:
            account: Account to bill
            line_items: List of dicts with keys: description, quantity, unit_price
            billing_email: Override billing email
            notes: Invoice notes
            due_date: Payment due date
        """
        invoice = Invoice.objects.create(
            account=account,
            invoice_number=InvoiceService.generate_invoice_number(account),
            billing_email=billing_email or account.billing_email or account.users.filter(role='owner').first().email,
            status='draft',
            currency='USD',
            notes=notes,
            invoice_date=timezone.now().date(),
            due_date=due_date or (timezone.now() + timedelta(days=30))
        )
        
        # Add all line items
        for item in line_items:
            invoice.add_line_item(
                description=item['description'],
                quantity=item.get('quantity', 1),
                unit_price=Decimal(str(item['unit_price'])),
                amount=Decimal(str(item.get('amount', item['quantity'] * item['unit_price'])))
            )
        
        invoice.calculate_totals()
        invoice.save()
        
        return invoice
    
    @staticmethod
    @transaction.atomic
    def mark_paid(
        invoice: Invoice,
        payment_method: str,
        transaction_id: Optional[str] = None
    ) -> Invoice:
        """
        Mark invoice as paid
        """
        invoice.status = 'paid'
        invoice.paid_at = timezone.now()
        invoice.save()
        
        return invoice
    
    @staticmethod
    @transaction.atomic
    def mark_void(invoice: Invoice, reason: Optional[str] = None) -> Invoice:
        """
        Void an invoice
        """
        if invoice.status == 'paid':
            raise ValueError("Cannot void a paid invoice")
        
        invoice.status = 'void'
        if reason:
            invoice.notes = f"{invoice.notes}\n\nVoided: {reason}" if invoice.notes else f"Voided: {reason}"
        invoice.save()
        
        return invoice
    
    @staticmethod
    def generate_pdf(invoice: Invoice) -> bytes:
        """
        Generate PDF for invoice
        
        TODO: Implement PDF generation using reportlab or weasyprint
        For now, return placeholder
        """
        from io import BytesIO
        
        # Placeholder - implement PDF generation
        buffer = BytesIO()
        
        # Simple text representation for now
        content = f"""
INVOICE #{invoice.invoice_number}

Bill To: {invoice.account.name}
Email: {invoice.billing_email}

Date: {invoice.created_at.strftime('%Y-%m-%d')}
Due Date: {invoice.due_date.strftime('%Y-%m-%d') if invoice.due_date else 'N/A'}

Line Items:
"""
        for item in invoice.line_items:
            content += f"  {item['description']} - ${item['amount']}\n"
        
        content += f"""
Subtotal: ${invoice.subtotal}
Tax: ${invoice.tax_amount}
Total: ${invoice.total_amount}

Status: {invoice.status.upper()}
"""
        
        buffer.write(content.encode('utf-8'))
        buffer.seek(0)
        
        return buffer.getvalue()
    
    @staticmethod
    def get_account_invoices(
        account: Account,
        status: Optional[str] = None,
        limit: int = 50
    ) -> List[Invoice]:
        """
        Get invoices for an account
        """
        queryset = Invoice.objects.filter(account=account)
        
        if status:
            queryset = queryset.filter(status=status)
        
        return list(queryset.order_by('-created_at')[:limit])
    
    @staticmethod
    def get_upcoming_renewals(days: int = 7) -> List[Subscription]:
        """
        Get subscriptions that will renew in the next N days
        """
        from django.utils import timezone
        from datetime import timedelta
        
        cutoff_date = timezone.now() + timedelta(days=days)
        
        return list(
            Subscription.objects.filter(
                status='active',
                current_period_end__lte=cutoff_date
            ).select_related('account', 'plan')
        )
