"""
Complete Finance & Accounting Models
Revenue, Expenses, Profit/Loss, Tax, Payroll, Invoices, Financial Reports
"""
from django.db import models
from django.utils import timezone
from decimal import Decimal
from django.core.validators import MinValueValidator
from datetime import timedelta


class FinancialAccount(models.Model):
    """
    Chart of Accounts - All financial accounts
    """
    ACCOUNT_TYPE_CHOICES = [
        ('ASSET', 'Asset'),
        ('LIABILITY', 'Liability'),
        ('EQUITY', 'Equity'),
        ('REVENUE', 'Revenue'),
        ('EXPENSE', 'Expense'),
    ]
    
    code = models.CharField(max_length=20, unique=True)
    name = models.CharField(max_length=200)
    account_type = models.CharField(max_length=20, choices=ACCOUNT_TYPE_CHOICES)
    description = models.TextField(blank=True)
    
    # Hierarchy
    parent_account = models.ForeignKey(
        'self',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='sub_accounts'
    )
    
    # Balance
    current_balance = models.DecimalField(max_digits=15, decimal_places=2, default=0)
    
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        ordering = ['code']
    
    def __str__(self):
        return f"{self.code} - {self.name}"


class Transaction(models.Model):
    """
    Financial Transactions (Double-Entry Bookkeeping)
    """
    TRANSACTION_TYPE_CHOICES = [
        ('SALE', 'Sale Revenue'),
        ('EXPENSE', 'Expense'),
        ('PAYMENT', 'Payment'),
        ('REFUND', 'Refund'),
        ('COMMISSION', 'Commission'),
        ('SUBSCRIPTION', 'Subscription'),
        ('PAYOUT', 'Vendor Payout'),
        ('TAX', 'Tax'),
        ('TRANSFER', 'Transfer'),
    ]
    
    transaction_number = models.CharField(max_length=50, unique=True)
    transaction_type = models.CharField(max_length=20, choices=TRANSACTION_TYPE_CHOICES)
    
    description = models.TextField()
    amount = models.DecimalField(max_digits=15, decimal_places=2, validators=[MinValueValidator(0)])
    
    # Double-Entry
    debit_account = models.ForeignKey(
        FinancialAccount,
        on_delete=models.PROTECT,
        related_name='debit_transactions'
    )
    credit_account = models.ForeignKey(
        FinancialAccount,
        on_delete=models.PROTECT,
        related_name='credit_transactions'
    )
    
    # References
    order = models.ForeignKey('orders.Order', on_delete=models.SET_NULL, null=True, blank=True)
    vendor = models.ForeignKey('vendors.Vendor', on_delete=models.SET_NULL, null=True, blank=True)
    
    # Metadata
    created_by = models.ForeignKey('accounts.User', on_delete=models.SET_NULL, null=True)
    transaction_date = models.DateTimeField(default=timezone.now)
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        ordering = ['-transaction_date']
    
    def __str__(self):
        return f"{self.transaction_number} - {self.description}"
    
    def save(self, *args, **kwargs):
        # Generate transaction number
        if not self.transaction_number:
            last_trans = Transaction.objects.order_by('-id').first()
            if last_trans:
                num = int(last_trans.transaction_number.split('-')[1]) + 1
            else:
                num = 1
            self.transaction_number = f"TXN-{num:06d}"
        
        super().save(*args, **kwargs)
        
        # Update account balances
        self.debit_account.current_balance += self.amount
        self.debit_account.save(update_fields=['current_balance'])
        
        self.credit_account.current_balance -= self.amount
        self.credit_account.save(update_fields=['current_balance'])


class Revenue(models.Model):
    """
    Revenue tracking
    """
    REVENUE_TYPE_CHOICES = [
        ('PRODUCT_SALE', 'Product Sales'),
        ('VENDOR_COMMISSION', 'Vendor Commission'),
        ('SUBSCRIPTION', 'Subscription Fees'),
        ('SHIPPING', 'Shipping Fees'),
        ('OTHER', 'Other Revenue'),
    ]
    
    revenue_type = models.CharField(max_length=30, choices=REVENUE_TYPE_CHOICES)
    description = models.CharField(max_length=300)
    
    gross_amount = models.DecimalField(max_digits=15, decimal_places=2)
    discount = models.DecimalField(max_digits=15, decimal_places=2, default=0)
    tax_amount = models.DecimalField(max_digits=15, decimal_places=2, default=0)
    net_amount = models.DecimalField(max_digits=15, decimal_places=2)
    
    # References
    order = models.ForeignKey('orders.Order', on_delete=models.SET_NULL, null=True, blank=True)
    vendor = models.ForeignKey('vendors.Vendor', on_delete=models.SET_NULL, null=True, blank=True)
    transaction = models.ForeignKey(Transaction, on_delete=models.SET_NULL, null=True)
    
    revenue_date = models.DateField(db_index=True)
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        ordering = ['-revenue_date']
    
    def __str__(self):
        return f"{self.get_revenue_type_display()} - ₹{self.net_amount}"
    
    def save(self, *args, **kwargs):
        # Calculate net amount
        self.net_amount = self.gross_amount - self.discount - self.tax_amount
        super().save(*args, **kwargs)


class Expense(models.Model):
    """
    Business expenses
    """
    EXPENSE_CATEGORY_CHOICES = [
        ('COGS', 'Cost of Goods Sold'),
        ('SHIPPING', 'Shipping & Delivery'),
        ('MARKETING', 'Marketing & Advertising'),
        ('HOSTING', 'Server & Hosting'),
        ('SOFTWARE', 'Software & Tools'),
        ('PAYROLL', 'Salaries & Wages'),
        ('RENT', 'Rent & Utilities'),
        ('INSURANCE', 'Insurance'),
        ('TAXES', 'Taxes'),
        ('BANK_FEES', 'Bank & Payment Fees'),
        ('REFUND', 'Refunds'),
        ('OTHER', 'Other Expenses'),
    ]
    
    expense_number = models.CharField(max_length=50, unique=True)
    category = models.CharField(max_length=30, choices=EXPENSE_CATEGORY_CHOICES)
    
    description = models.TextField()
    amount = models.DecimalField(max_digits=15, decimal_places=2, validators=[MinValueValidator(0)])
    tax_amount = models.DecimalField(max_digits=15, decimal_places=2, default=0)
    
    # Vendor/Supplier
    vendor_name = models.CharField(max_length=200, blank=True)
    invoice_number = models.CharField(max_length=100, blank=True)
    receipt = models.FileField(upload_to='expenses/receipts/', blank=True)
    
    # Payment
    payment_method = models.CharField(max_length=50, blank=True)
    payment_status = models.CharField(
        max_length=20,
        choices=[
            ('PENDING', 'Pending'),
            ('PAID', 'Paid'),
            ('OVERDUE', 'Overdue'),
        ],
        default='PENDING'
    )
    
    # References
    transaction = models.ForeignKey(Transaction, on_delete=models.SET_NULL, null=True)
    
    # Dates
    expense_date = models.DateField(db_index=True)
    due_date = models.DateField(blank=True, null=True)
    paid_date = models.DateField(blank=True, null=True)
    
    created_at = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey('accounts.User', on_delete=models.SET_NULL, null=True)
    
    class Meta:
        ordering = ['-expense_date']
    
    def __str__(self):
        return f"{self.expense_number} - {self.get_category_display()}"
    
    def save(self, *args, **kwargs):
        if not self.expense_number:
            last_exp = Expense.objects.order_by('-id').first()
            if last_exp:
                num = int(last_exp.expense_number.split('-')[1]) + 1
            else:
                num = 1
            self.expense_number = f"EXP-{num:06d}"
        super().save(*args, **kwargs)


class Invoice(models.Model):
    """
    Invoices (for B2B sales or vendor payouts)
    """
    STATUS_CHOICES = [
        ('DRAFT', 'Draft'),
        ('SENT', 'Sent'),
        ('PAID', 'Paid'),
        ('OVERDUE', 'Overdue'),
        ('CANCELLED', 'Cancelled'),
    ]
    
    invoice_number = models.CharField(max_length=50, unique=True)
    
    # Client/Vendor
    client_name = models.CharField(max_length=200)
    client_email = models.EmailField()
    client_address = models.TextField(blank=True)
    
    # Amounts
    subtotal = models.DecimalField(max_digits=15, decimal_places=2)
    tax_rate = models.DecimalField(max_digits=5, decimal_places=2, default=0)
    tax_amount = models.DecimalField(max_digits=15, decimal_places=2, default=0)
    total = models.DecimalField(max_digits=15, decimal_places=2)
    
    # Status
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='DRAFT')
    
    # Dates
    invoice_date = models.DateField()
    due_date = models.DateField()
    paid_date = models.DateField(blank=True, null=True)
    
    # Notes
    notes = models.TextField(blank=True)
    terms = models.TextField(blank=True)
    
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        ordering = ['-invoice_date']
    
    def __str__(self):
        return f"{self.invoice_number} - {self.client_name}"


class TaxRecord(models.Model):
    """
    Tax calculations and records
    """
    TAX_TYPE_CHOICES = [
        ('SALES_TAX', 'Sales Tax'),
        ('VAT', 'VAT'),
        ('INCOME_TAX', 'Income Tax'),
        ('PAYROLL_TAX', 'Payroll Tax'),
    ]
    
    tax_type = models.CharField(max_length=20, choices=TAX_TYPE_CHOICES)
    description = models.CharField(max_length=300)
    
    tax_rate = models.DecimalField(max_digits=5, decimal_places=2)
    taxable_amount = models.DecimalField(max_digits=15, decimal_places=2)
    tax_amount = models.DecimalField(max_digits=15, decimal_places=2)
    
    # Period
    period_start = models.DateField()
    period_end = models.DateField()
    
    # Payment
    is_paid = models.BooleanField(default=False)
    paid_date = models.DateField(blank=True, null=True)
    
    transaction = models.ForeignKey(Transaction, on_delete=models.SET_NULL, null=True)
    
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        ordering = ['-period_end']
    
    def __str__(self):
        return f"{self.get_tax_type_display()} - {self.period_start} to {self.period_end}"


class FinancialReport(models.Model):
    """
    Generated financial reports
    """
    REPORT_TYPE_CHOICES = [
        ('INCOME_STATEMENT', 'Income Statement (P&L)'),
        ('BALANCE_SHEET', 'Balance Sheet'),
        ('CASH_FLOW', 'Cash Flow Statement'),
        ('TAX_REPORT', 'Tax Report'),
        ('VENDOR_PAYOUT', 'Vendor Payout Report'),
    ]
    
    report_type = models.CharField(max_length=30, choices=REPORT_TYPE_CHOICES)
    report_name = models.CharField(max_length=200)
    
    # Period
    period_start = models.DateField()
    period_end = models.DateField()
    
    # Summary Data
    total_revenue = models.DecimalField(max_digits=15, decimal_places=2, default=0)
    total_expenses = models.DecimalField(max_digits=15, decimal_places=2, default=0)
    net_profit = models.DecimalField(max_digits=15, decimal_places=2, default=0)
    
    # Report File
    report_file = models.FileField(upload_to='financial_reports/', blank=True)
    report_data = models.JSONField(blank=True, null=True)
    
    generated_at = models.DateTimeField(auto_now_add=True)
    generated_by = models.ForeignKey('accounts.User', on_delete=models.SET_NULL, null=True)
    
    class Meta:
        ordering = ['-generated_at']
    
    def __str__(self):
        return f"{self.report_name} ({self.period_start} to {self.period_end})"


class Budget(models.Model):
    """
    Budget planning
    """
    name = models.CharField(max_length=200)
    description = models.TextField(blank=True)
    
    # Period
    fiscal_year = models.IntegerField()
    period_start = models.DateField()
    period_end = models.DateField()
    
    # Budget amounts by category
    revenue_budget = models.DecimalField(max_digits=15, decimal_places=2)
    expense_budget = models.DecimalField(max_digits=15, decimal_places=2)
    profit_target = models.DecimalField(max_digits=15, decimal_places=2)
    
    # Actuals (auto-calculated)
    actual_revenue = models.DecimalField(max_digits=15, decimal_places=2, default=0)
    actual_expenses = models.DecimalField(max_digits=15, decimal_places=2, default=0)
    actual_profit = models.DecimalField(max_digits=15, decimal_places=2, default=0)
    
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        ordering = ['-fiscal_year']
    
    def __str__(self):
        return f"{self.name} - FY {self.fiscal_year}"
    
    @property
    def revenue_variance(self):
        return self.actual_revenue - self.revenue_budget
    
    @property
    def expense_variance(self):
        return self.expense_budget - self.actual_expenses
    
    @property
    def budget_utilization(self):
        if self.expense_budget > 0:
            return (self.actual_expenses / self.expense_budget) * 100
        return 0
