from email.policy import default
import uuid
import os
from datetime import date
from django.conf import settings
from django.db import models
from django.template.loader import render_to_string
from crm.models import Lead, Quote
from lib.sevices import generate_amount_in_words
from lib.choices import choices_the_options
from utils.currency import CurrencyType
from crm.models.invoice_generator import InvoiceGenerator


class Invoice(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    quote = models.ForeignKey(Quote, on_delete=models.SET_NULL, null=True, blank=True)
    invoice_number = models.CharField(max_length=20, unique=True)
    invoice_date = models.DateField()
    lead = models.ForeignKey(Lead, on_delete=models.CASCADE, related_name='invoices')
    office = models.ForeignKey('crm.Office', on_delete=models.SET_NULL, null=True, blank=True,
                              help_text="Office location for this invoice")
    currency = models.CharField(max_length=3, choices=choices_the_options(CurrencyType), default=CurrencyType.INR.value)
    gst = models.DecimalField(max_digits=5, decimal_places=2, default=0.0, help_text="GST percentage")
    created_at = models.DateTimeField(auto_now_add=True)
    remarks = models.TextField(blank=True, null=True)
    terms_and_conditions = models.TextField(blank=True, null=True)
    pdf_file = models.FileField(upload_to='media/invoices/', null=True, blank=True)
    mark_as_sent = models.BooleanField(default=False)
    approved = models.BooleanField(default=False)
    pending_amount = models.DecimalField(max_digits=10, decimal_places=2, default=0.0)
    is_paid = models.BooleanField(default=False)

    def __str__(self):
        return str(self.invoice_number)

    class Meta:
        ordering = ['-created_at']

    def save(self, *args, **kwargs):
        # Set default office if none specified
        if not self.office:
            from crm.models.office import Office
            self.office = Office.get_default_office()
        super().save(*args, **kwargs)

    def get_invoice_data_for_generator(self):
        """Convert Django model data to format expected by InvoiceGenerator"""
        items = self.items.all()

        # Calculate totals
        subtotal = sum(float(item.amount) for item in items)
        total = subtotal

        # Convert items to expected format
        items_data = []
        for item in items:
            items_data.append({
                'description': item.item_name,
                'notes': item.description,
                'quantity': float(item.qty),
                'rate': float(item.rate),
                'amount': float(item.amount)
            })

        # Get lead data
        lead_data = {}
        if self.lead:
            lead_data = {
                'company': self.lead.company or '',
                'first_name': self.lead.first_name or '',
                'last_name': self.lead.last_name or '',
                'address': self.lead.address or '',
                'city': self.lead.city or '',
                'state': self.lead.state or '',
                'zip_code': self.lead.zip_code or '',
                'country': self.lead.country or '',
            }

        lead_data['remarks'] = self.remarks
        lead_data['terms_and_conditions'] = self.terms_and_conditions

        # Generate amount in words
        amount_in_words = generate_amount_in_words(total)

        # Get office information
        office_info = {}
        if self.office:
            office_info = self.office.get_company_info()

        return {
            'invoice_number': self.invoice_number,
            'invoice_date': self.invoice_date.strftime('%d %b %Y'),
            'due_date': self.invoice_date.strftime('%d %b %Y'),  # Using invoice date as due date
            'terms': 'Due On Receipt',
            'client_name': f"{lead_data.get('company', '')} {lead_data.get('first_name', '')} {lead_data.get('last_name', '')}".strip(),
            'client_address': f"{lead_data.get('address', '')}, {lead_data.get('city', '')}, {lead_data.get('state', '')} {lead_data.get('zip_code', '')}, {lead_data.get('country', '')}".strip(', '),
            'items': items_data,
            'subtotal': subtotal,
            'total': total,
            'balance_due': total,
            'amount_in_words': amount_in_words,
            'notes': 'Thanks for your business.',
            'currency': self.currency,
            'office_info': office_info
        }

    def generate_pdf(self):
        """Generate PDF using InvoiceGenerator templates"""
        items = self.items.all()
        if not items.exists() and self.quote:
            for quote_item in self.quote.items.all():
                from crm.models import InvoiceItem
                InvoiceItem.objects.create(
                    invoice=self,
                    item_name=quote_item.item_name,
                    description=quote_item.description,
                    qty=quote_item.qty,
                    rate=quote_item.rate,
                    amount=quote_item.amount,
                )
            items = self.items.all()

        # Ensure invoice has an office; fallback to quote.office
        if not self.office and self.quote and getattr(self.quote, 'office', None):
            self.office = self.quote.office
            self.save(update_fields=['office'])

        # Get invoice data in the format expected by InvoiceGenerator
        invoice_data = self.get_invoice_data_for_generator()

        # Create invoices directory
        invoices_dir = os.path.join(settings.MEDIA_ROOT, "invoices")
        os.makedirs(invoices_dir, exist_ok=True)

        try:
            # Initialize the InvoiceGenerator with office info
            office_info = invoice_data.get('office_info', {})
            generator = InvoiceGenerator(office_info=office_info)

            # Generate HTML content
            html_content = generator.generate_invoice_html(invoice_data)

            print(html_content, "INVOICE HTML")

            # Generate HTML file using the generator's method
            html_path = os.path.join(invoices_dir, f"{self.invoice_number}.html")
            generator.save_html_file(html_content, html_path)

            # Update the model's pdf_file field
            self.pdf_file.name = f"invoices/{self.invoice_number}.html"
            self.save(update_fields=["pdf_file"])

        except Exception as e:
            print(f"Error generating invoice files: {e}")
            raise e



    def get_total_paid(self):
        """Calculate total amount paid for this invoice"""
        return sum(float(payment.amount) for payment in self.payments.all())
    
    def get_pending_amount(self):
        """Calculate pending amount for this invoice"""
        total_amount = sum(float(item.amount) for item in self.items.all())
        total_paid = self.get_total_paid()
        return max(0, total_amount - total_paid)
    
    def ensure_items_from_quote(self):
        if self.quote and self.items.count() == 0:
            for quote_item in self.quote.items.all():
                from crm.models import InvoiceItem
                InvoiceItem.objects.create(
                    invoice=self,
                    item_name=quote_item.item_name,
                    description=quote_item.description,
                    qty=quote_item.qty,
                    rate=quote_item.rate,
                    amount=quote_item.amount,
                )
            self.generate_pdf()


class InvoiceItem(models.Model):
    invoice = models.ForeignKey(Invoice, on_delete=models.CASCADE, related_name='items')
    item_name = models.CharField(max_length=255)
    description = models.TextField(blank=True)
    qty = models.IntegerField()
    rate = models.DecimalField(max_digits=10, decimal_places=2)
    amount = models.DecimalField(max_digits=10, decimal_places=2)

    def __str__(self):
        return str(self.item_name)
