
from django.db import models
from django.contrib.auth import get_user_model
from django.utils import timezone
from decimal import Decimal
from hr.models import Employee, Department
import uuid

User = get_user_model()

class ExpenseCategory(models.Model):
    name = models.CharField(max_length=100, unique=True)
    description = models.TextField(blank=True)
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    def __str__(self):
        return self.name
    
    class Meta:
        ordering = ['name']
        verbose_name_plural = "Expense Categories"

class BudgetAllocation(models.Model):
    ALLOCATION_PERIOD_CHOICES = [
        ('monthly', 'Monthly'),
        ('quarterly', 'Quarterly'),
        ('yearly', 'Yearly'),
    ]
    
    employee = models.ForeignKey(Employee, on_delete=models.CASCADE, related_name='budget_allocations')
    category = models.ForeignKey(ExpenseCategory, on_delete=models.CASCADE, related_name='allocations')
    allocated_amount = models.DecimalField(max_digits=12, decimal_places=2)
    spent_amount = models.DecimalField(max_digits=12, decimal_places=2, default=Decimal('0.00'))
    allocation_period = models.CharField(max_length=20, choices=ALLOCATION_PERIOD_CHOICES, default='monthly')
    start_date = models.DateField()
    end_date = models.DateField()
    notes = models.TextField(blank=True)
    is_active = models.BooleanField(default=True)
    created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='created_allocations')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    @property
    def remaining_amount(self):
        return self.allocated_amount - self.spent_amount
    
    @property
    def utilization_percentage(self):
        if self.allocated_amount > 0:
            return (self.spent_amount / self.allocated_amount) * 100
        return 0
    
    def __str__(self):
        return f"{self.employee.full_name} - {self.category.name}: KSh {self.allocated_amount}"
    
    class Meta:
        ordering = ['-created_at']
        unique_together = ['employee', 'category', 'start_date', 'end_date']

class Expense(models.Model):
    STATUS_CHOICES = [
        ('pending', 'Pending Approval'),
        ('approved', 'Approved'),
        ('rejected', 'Rejected'),
        ('paid', 'Paid'),
    ]
    
    expense_number = models.CharField(max_length=50, unique=True, editable=False)
    employee = models.ForeignKey(Employee, on_delete=models.CASCADE, related_name='expenses')
    category = models.ForeignKey(ExpenseCategory, on_delete=models.CASCADE, related_name='expenses')
    budget_allocation = models.ForeignKey(BudgetAllocation, on_delete=models.SET_NULL, null=True, blank=True)
    
    # Link to payslip for salary/bonus expenses
    related_payslip = models.ForeignKey('hr.Payslip', on_delete=models.SET_NULL, null=True, blank=True, related_name='expenses')
    
    # Expense Details
    title = models.CharField(max_length=200, help_text="Brief description of the expense")
    description = models.TextField(help_text="Detailed description of what this expense is for")
    amount = models.DecimalField(max_digits=12, decimal_places=2)
    expense_date = models.DateField(default=timezone.now)
    
    # Vendor/Supplier Information
    vendor_name = models.CharField(max_length=200, blank=True, help_text="Name of vendor/supplier")
    vendor_contact = models.CharField(max_length=100, blank=True, help_text="Vendor contact info")
    
    # Approval Workflow
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
    submitted_at = models.DateTimeField(auto_now_add=True)
    approved_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='approved_expenses')
    approved_at = models.DateTimeField(null=True, blank=True)
    rejected_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='rejected_expenses')
    rejected_at = models.DateTimeField(null=True, blank=True)
    rejection_reason = models.TextField(blank=True)
    
    # Payment Information
    paid_at = models.DateTimeField(null=True, blank=True)
    payment_method = models.CharField(max_length=50, blank=True)
    payment_reference = models.CharField(max_length=100, blank=True)
    
    # Additional Information
    notes = models.TextField(blank=True)
    is_reimbursable = models.BooleanField(default=True, help_text="Should this expense be reimbursed to the employee?")
    
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    def save(self, *args, **kwargs):
        if not self.expense_number:
            # Generate unique expense number
            year_month = timezone.now().strftime('%Y%m')
            last_expense = Expense.objects.filter(
                expense_number__startswith=f'EXP{year_month}'
            ).order_by('-expense_number').first()
            
            if last_expense:
                last_number = int(last_expense.expense_number[-4:])
                new_number = last_number + 1
            else:
                new_number = 1
            
            self.expense_number = f"EXP{year_month}{new_number:04d}"
        
        super().save(*args, **kwargs)
        
        # Update budget allocation spent amount
        if self.budget_allocation and self.status in ['approved', 'paid']:
            total_spent = Expense.objects.filter(
                budget_allocation=self.budget_allocation,
                status__in=['approved', 'paid']
            ).aggregate(total=models.Sum('amount'))['total'] or Decimal('0.00')
            
            self.budget_allocation.spent_amount = total_spent
            self.budget_allocation.save()
    
    def __str__(self):
        return f"{self.expense_number} - {self.title}"
    
    class Meta:
        ordering = ['-submitted_at']

class ExpenseAttachment(models.Model):
    ATTACHMENT_TYPE_CHOICES = [
        ('receipt', 'Receipt'),
        ('invoice', 'Invoice'),
        ('photo', 'Photo'),
        ('document', 'Document'),
        ('other', 'Other'),
    ]
    
    expense = models.ForeignKey(Expense, on_delete=models.CASCADE, related_name='attachments')
    attachment_type = models.CharField(max_length=20, choices=ATTACHMENT_TYPE_CHOICES, default='receipt')
    title = models.CharField(max_length=200, help_text="Description of the attachment")
    file = models.FileField(upload_to='expenses/attachments/')
    uploaded_at = models.DateTimeField(auto_now_add=True)
    file_size = models.PositiveIntegerField(help_text="File size in bytes", editable=False)
    
    def save(self, *args, **kwargs):
        if self.file:
            self.file_size = self.file.size
        super().save(*args, **kwargs)
    
    @property
    def file_size_formatted(self):
        """Return file size in human readable format"""
        if self.file_size:
            size = self.file_size
            for unit in ['B', 'KB', 'MB', 'GB']:
                if size < 1024:
                    return f"{size:.1f} {unit}"
                size /= 1024
            return f"{size:.1f} TB"
        return "Unknown"
    
    def __str__(self):
        return f"{self.expense.expense_number} - {self.title}"
    
    class Meta:
        ordering = ['-uploaded_at']

class ExpenseApprovalLog(models.Model):
    ACTION_CHOICES = [
        ('submitted', 'Submitted'),
        ('approved', 'Approved'),
        ('rejected', 'Rejected'),
        ('paid', 'Marked as Paid'),
        ('modified', 'Modified'),
    ]
    
    expense = models.ForeignKey(Expense, on_delete=models.CASCADE, related_name='approval_logs')
    action = models.CharField(max_length=20, choices=ACTION_CHOICES)
    performed_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    comments = models.TextField(blank=True)
    timestamp = models.DateTimeField(auto_now_add=True)
    
    def __str__(self):
        return f"{self.expense.expense_number} - {self.get_action_display()}"
    
    class Meta:
        ordering = ['-timestamp']
