from django.db import models
from django.contrib.auth import get_user_model
from django.core.validators import MinValueValidator, MaxValueValidator
from django.utils.translation import gettext_lazy as _
from decimal import Decimal

User = get_user_model()

class Category(models.Model):
    """Product categories"""
    name = models.CharField(max_length=100, unique=True)
    description = models.TextField(blank=True)
    parent = models.ForeignKey('self', on_delete=models.CASCADE, blank=True, null=True, related_name='children')
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        verbose_name = _('Category')
        verbose_name_plural = _('Categories')
        ordering = ['name']
    
    def __str__(self):
        return self.name
    
    def get_full_path(self):
        """Get full category path including parent categories"""
        if self.parent:
            return f"{self.parent.get_full_path()} > {self.name}"
        return self.name

class Product(models.Model):
    """Product model for inventory management"""
    
    UNIT_CHOICES = [
        ('pcs', 'Pieces'),
        ('kg', 'Kilograms'),
        ('m', 'Meters'),
        ('l', 'Liters'),
        ('box', 'Boxes'),
        ('set', 'Sets'),
    ]
    
    name = models.CharField(max_length=200)
    code = models.CharField(max_length=50, unique=True, help_text='Unique product code/SKU')
    description = models.TextField(blank=True)
    category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, blank=True)
    
    # Stock information
    current_stock = models.DecimalField(
        max_digits=10, 
        decimal_places=2, 
        default=0,
        validators=[MinValueValidator(Decimal('0'))]
    )
    min_stock_level = models.DecimalField(
        max_digits=10, 
        decimal_places=2, 
        default=0,
        validators=[MinValueValidator(Decimal('0'))]
    )
    max_stock_level = models.DecimalField(
        max_digits=10, 
        decimal_places=2, 
        default=1000,
        validators=[MinValueValidator(Decimal('0'))]
    )
    
    # Pricing
    cost_price = models.DecimalField(
        max_digits=10, 
        decimal_places=2, 
        default=0,
        validators=[MinValueValidator(Decimal('0'))]
    )
    selling_price = models.DecimalField(
        max_digits=10, 
        decimal_places=2, 
        default=0,
        validators=[MinValueValidator(Decimal('0'))]
    )
    
    # Product details
    unit = models.CharField(max_length=10, choices=UNIT_CHOICES, default='pcs')
    weight = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
    dimensions = models.CharField(max_length=100, blank=True, help_text='Format: LxWxH in cm')
    
    # Status
    is_active = models.BooleanField(default=True)
    is_manufactured = models.BooleanField(default=False, help_text='Is this a manufactured product?')
    
    # Timestamps
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        ordering = ['name']
        verbose_name = _('Product')
        verbose_name_plural = _('Products')
    
    def __str__(self):
        return f"{self.name} ({self.code})"
    
    def get_stock_status(self):
        """Get stock status for the product"""
        if self.current_stock <= self.min_stock_level:
            return 'low'
        elif self.current_stock >= self.max_stock_level:
            return 'high'
        else:
            return 'normal'
    
    def get_stock_value(self):
        """Calculate total stock value"""
        return self.current_stock * self.cost_price
    
    def is_low_stock(self):
        """Check if product has low stock"""
        return self.current_stock <= self.min_stock_level
    
    def is_overstocked(self):
        """Check if product is overstocked"""
        return self.current_stock >= self.max_stock_level

class StockMovement(models.Model):
    """Track all stock movements (in/out)"""
    
    MOVEMENT_TYPES = [
        ('in', 'Stock In'),
        ('out', 'Stock Out'),
        ('adjustment', 'Stock Adjustment'),
        ('manufacturing', 'Manufacturing Output'),
        ('sale', 'Sale'),
        ('purchase', 'Purchase'),
    ]
    
    product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='stock_movements')
    movement_type = models.CharField(max_length=20, choices=MOVEMENT_TYPES)
    quantity = models.DecimalField(max_digits=10, decimal_places=2)
    unit_price = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
    total_value = models.DecimalField(max_digits=12, decimal_places=2, blank=True, null=True)
    
    # Reference fields for different movement types
    reference_type = models.CharField(max_length=50, blank=True, help_text='Type of reference document')
    reference_id = models.IntegerField(blank=True, null=True, help_text='ID of reference document')
    reference_note = models.CharField(max_length=200, blank=True)
    
    # Movement details
    date = models.DateField()
    notes = models.TextField(blank=True)
    
    # User tracking
    created_by = models.ForeignKey('users.CustomUser', on_delete=models.SET_NULL, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        ordering = ['-date', '-created_at']
        verbose_name = _('Stock Movement')
        verbose_name_plural = _('Stock Movements')
    
    def __str__(self):
        return f"{self.product.name} - {self.get_movement_type_display()} ({self.quantity})"
    
    def save(self, *args, **kwargs):
        """Override save to calculate total value and update product stock"""
        if self.unit_price and self.quantity:
            self.total_value = self.unit_price * self.quantity
        
        # Update product stock
        if self.pk:  # Existing movement - revert old quantity
            old_movement = StockMovement.objects.get(pk=self.pk)
            if old_movement.movement_type == 'in':
                self.product.current_stock -= old_movement.quantity
            elif old_movement.movement_type == 'out':
                self.product.current_stock += old_movement.quantity
        
        # Apply new movement
        if self.movement_type == 'in':
            self.product.current_stock += self.quantity
        elif self.movement_type == 'out':
            self.product.current_stock -= self.quantity
        elif self.movement_type == 'adjustment':
            # For adjustments, quantity is the new stock level
            self.product.current_stock = self.quantity
        
        # Ensure stock doesn't go negative
        if self.product.current_stock < 0:
            self.product.current_stock = 0
        
        self.product.save()
        super().save(*args, **kwargs)
    
    def delete(self, *args, **kwargs):
        """Override delete to revert stock changes"""
        if self.movement_type == 'in':
            self.product.current_stock -= self.quantity
        elif self.movement_type == 'out':
            self.product.current_stock += self.quantity
        
        self.product.save()
        super().delete(*args, **kwargs)

class Customer(models.Model):
    """Customer model"""
    CUSTOMER_TYPE_CHOICES = [
        ('retail', 'Retail'),
        ('wholesale', 'Wholesale'),
        ('corporate', 'Corporate'),
    ]
    
    code = models.CharField(max_length=50, unique=True)
    name = models.CharField(max_length=200)
    customer_type = models.CharField(max_length=20, choices=CUSTOMER_TYPE_CHOICES, default='retail')
    contact_person = models.CharField(max_length=100, blank=True)
    email = models.EmailField(blank=True)
    phone = models.CharField(max_length=20, blank=True)
    address = models.TextField(blank=True)
    credit_limit = models.DecimalField(max_digits=12, decimal_places=2, default=0)
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        ordering = ['name']
    
    def __str__(self):
        return f"{self.code} - {self.name}"

class Supplier(models.Model):
    """Supplier model"""
    code = models.CharField(max_length=50, unique=True)
    name = models.CharField(max_length=200)
    contact_person = models.CharField(max_length=100, blank=True)
    email = models.EmailField(blank=True)
    phone = models.CharField(max_length=20, blank=True)
    address = models.TextField(blank=True)
    rating = models.PositiveSmallIntegerField(
        validators=[MinValueValidator(1), MaxValueValidator(5)],
        default=3
    )
    credit_limit = models.DecimalField(max_digits=12, decimal_places=2, default=0)
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        ordering = ['name']
    
    def __str__(self):
        return f"{self.code} - {self.name}"
