"""
Product Models for E-commerce Platform
Includes: Category, Product, ProductImage, ProductVariation, Review
"""
from django.db import models
from django.utils.text import slugify
from django.core.validators import MinValueValidator, MaxValueValidator
from django.conf import settings
import random
import string
import os
import re
# from imagekit.models import ImageSpecField  # Not installed yet
# from imagekit.processors import ResizeToFill  # Not installed yet


def _seg(name):
    s = (name or '').strip()
    s = re.sub(r'[^A-Za-z0-9_.-]+', '_', s)
    s = s.strip('_.')
    return s or 'unknown'


def upload_product_featured_image(instance, filename):
    product = instance
    vendor_code = ''
    if product.vendor and getattr(product.vendor, 'vendor_code', None):
        vendor_code = product.vendor.vendor_code
    else:
        vendor_code = 'site'
    cat = _seg(getattr(product.category, 'name', '') if product.category_id else '')
    pname = _seg(product.name)
    bname = _seg(product.brand)
    base_dir = f"vendors/{vendor_code}/{cat}/{pname}/{bname}"
    name, ext = os.path.splitext(filename)
    ext = (ext or '.jpg').lower()
    return f"{base_dir}/featured{ext}"


def upload_product_gallery_image(instance, filename):
    product = instance.product
    vendor_code = ''
    if product.vendor and getattr(product.vendor, 'vendor_code', None):
        vendor_code = product.vendor.vendor_code
    else:
        vendor_code = 'site'
    cat = _seg(getattr(product.category, 'name', '') if product.category_id else '')
    pname = _seg(product.name)
    bname = _seg(product.brand)
    base_dir = f"vendors/{vendor_code}/{cat}/{pname}/{bname}"
    name, ext = os.path.splitext(filename)
    ext = (ext or '.jpg').lower()
    idx = (product.images.count() or 0) + 1
    return f"{base_dir}/{idx:03d}{ext}"

class Category(models.Model):
    """Product Categories with hierarchical structure"""
    
    name = models.CharField(max_length=200, unique=True)
    slug = models.SlugField(max_length=200, unique=True, blank=True)
    description = models.TextField(blank=True)
    parent = models.ForeignKey(
        'self',
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='children'
    )
    image = models.ImageField(upload_to='categories/', blank=True, null=True)
    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_plural = 'Categories'
        ordering = ['name']
    
    def __str__(self):
        return self.name
    
    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.name)
        super().save(*args, **kwargs)
    
    @property
    def product_count(self):
        return self.products.filter(is_active=True).count()


class Brand(models.Model):
    """Admin-managed Brands"""
    name = models.CharField(max_length=200, unique=True)
    slug = models.SlugField(max_length=200, unique=True, blank=True)
    description = models.TextField(blank=True)
    logo = models.ImageField(upload_to='brands/', blank=True, null=True)
    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 self.name

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.name)
        super().save(*args, **kwargs)


class Product(models.Model):
    """Main Product Model"""
    
    # Basic Information
    name = models.CharField(max_length=300)
    slug = models.SlugField(max_length=300, unique=True, blank=True)
    sku = models.CharField(max_length=100, unique=True, verbose_name='Product Code', blank=True, null=True)
    description = models.TextField(blank=True)
    details = models.TextField(default='', blank=True)
    short_description = models.TextField(max_length=500, blank=True)
    
    # Category & Brand
    category = models.ForeignKey(
        Category,
        on_delete=models.CASCADE,
        related_name='products'
    )
    brand = models.CharField(max_length=100, blank=True) # Deprecated, use brand_ref
    brand_ref = models.ForeignKey(
        Brand,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='products',
        verbose_name='Brand'
    )
    unique_code = models.CharField(max_length=10, unique=True, blank=True, null=True)
    
    # Vendor (for multi-vendor marketplace)
    vendor = models.ForeignKey(
        'vendors.Vendor',
        on_delete=models.CASCADE,
        related_name='products',
        null=True,
        blank=True,
        help_text="Leave empty for site-owned products"
    )
    store = models.ForeignKey(
        'vendors.VendorStore',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='products'
    )
    
    # Pricing
    price = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        validators=[MinValueValidator(0)],
        blank=True,
        null=True
    )
    compare_price = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        null=True,
        blank=True,
        validators=[MinValueValidator(0)],
        help_text="Original price for discount display"
    )
    sale_price = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        null=True,
        blank=True,
        validators=[MinValueValidator(0)]
    )
    sale_start = models.DateTimeField(null=True, blank=True)
    sale_end = models.DateTimeField(null=True, blank=True)
    cost_price = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        null=True,
        blank=True,
        validators=[MinValueValidator(0)],
        help_text="Cost price for profit calculation"
    )
    
    # Inventory
    stock = models.IntegerField(
        default=0,
        validators=[MinValueValidator(0)]
    )
    low_stock_threshold = models.IntegerField(
        default=10,
        validators=[MinValueValidator(0)]
    )
    track_inventory = models.BooleanField(default=True)
    
    # Images
    featured_image = models.ImageField(upload_to=upload_product_featured_image, blank=True, null=True)
    video_url = models.URLField(blank=True, null=True, help_text="Product video URL (YouTube/Vimeo)")
    # featured_thumbnail = ImageSpecField(  # Not installed yet
    #     source='featured_image',
    #     processors=[ResizeToFill(300, 300)],
    #     format='JPEG',
    #     options={'quality': 85}
    # )
    
    # Status & Visibility
    is_active = models.BooleanField(default=True)
    is_featured = models.BooleanField(default=False)
    is_new_arrival = models.BooleanField(default=False)
    is_best_seller = models.BooleanField(default=False)
    
    # SEO
    meta_title = models.CharField(max_length=200, blank=True)
    meta_description = models.TextField(max_length=300, blank=True)
    meta_keywords = models.CharField(max_length=500, blank=True)
    
    # Statistics
    views_count = models.IntegerField(default=0)
    sales_count = models.IntegerField(default=0)
    
    # Product Approval Workflow
    APPROVAL_STATUS_CHOICES = [
        ('DRAFT', 'Draft'),
        ('PENDING', 'Pending Approval'),
        ('APPROVED', 'Approved'),
        ('REJECTED', 'Rejected'),
    ]
    
    approval_status = models.CharField(
        max_length=20,
        choices=APPROVAL_STATUS_CHOICES,
        default='DRAFT',
        help_text='Product approval status for staff review'
    )
    reviewed_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='reviewed_products',
        help_text='Staff member who reviewed this product'
    )
    reviewed_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text='When the product was reviewed'
    )
    rejection_reason = models.TextField(
        blank=True,
        help_text='Reason for rejection (shown to vendor)'
    )
    
    # Timestamps
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['slug']),
            models.Index(fields=['sku']),
            models.Index(fields=['category']),
            models.Index(fields=['-created_at']),
        ]
    
    def __str__(self):
        return self.name
    
    def save(self, *args, **kwargs):
        if self.brand_ref:
            self.brand = self.brand_ref.name
        
        # Ensure slug is unique
        if not self.slug:
            base_slug = slugify(self.name)
            self.slug = base_slug
            # If slug exists, append random suffix until unique
            while type(self).objects.filter(slug=self.slug).exclude(id=self.id).exists():
                suffix = ''.join(random.choices(string.ascii_lowercase + string.digits, k=4))
                self.slug = f"{base_slug}-{suffix}"
        
        if not self.unique_code:
            for _ in range(100):
                code = ''.join(random.choices(string.ascii_uppercase, k=2)) + ''.join(random.choices(string.digits, k=6)) + ''.join(random.choices(string.ascii_uppercase, k=2))
                if not type(self).objects.filter(unique_code=code).exists():
                    self.unique_code = code
                    break
        super().save(*args, **kwargs)
    
    @property
    def discount_percentage(self):
        base = self.compare_price if self.compare_price and self.compare_price > 0 else self.price
        current = self.sale_price if self.is_sale_active and self.sale_price else self.price
        if base and current and base > current:
            return int(((base - current) / base) * 100)
        return 0
    
    @property
    def average_rating(self):
        reviews = self.reviews.filter(is_approved=True)
        if reviews.exists():
            return round(reviews.aggregate(models.Avg('rating'))['rating__avg'], 1)
        return 0
    
    @property
    def review_count(self):
        return self.reviews.filter(is_approved=True).count()
    
    @property
    def is_in_stock(self):
        if not self.track_inventory:
            return True
        return self.stock > 0
    
    @property
    def is_low_stock(self):
        return self.track_inventory and self.stock <= self.low_stock_threshold
    
    @property
    def is_sale_active(self):
        from django.utils import timezone
        if not self.sale_price:
            return False
        now = timezone.now()
        if self.sale_start and self.sale_end:
            return self.sale_start <= now <= self.sale_end
        if self.sale_start and not self.sale_end:
            return self.sale_start <= now
        if self.sale_end and not self.sale_start:
            return now <= self.sale_end
        return True
    
    @property
    def sale_seconds_remaining(self):
        from django.utils import timezone
        if not self.is_sale_active or not self.sale_end:
            return None
        delta = self.sale_end - timezone.now()
        return int(delta.total_seconds()) if delta.total_seconds() > 0 else 0

    def get_variation_fields(self):
        """Get product specifications from variations"""
        fields = []
        # Get the first active variation to display default specs
        variation = self.variations.filter(is_active=True).first()
        if variation:
            if variation.length and variation.length > 0:
                fields.append(('Length', f"{variation.length} {variation.dimension_unit}"))
            if variation.width and variation.width > 0:
                fields.append(('Width', f"{variation.width} {variation.dimension_unit}"))
            if variation.height and variation.height > 0:
                fields.append(('Height', f"{variation.height} {variation.dimension_unit}"))
            if variation.quantity_value and variation.quantity_value > 0:
                fields.append(('Quantity', f"{variation.quantity_value} {variation.quantity_unit}"))
        return fields


def _seg(name):
    s = (name or '').strip()
    s = re.sub(r'[^A-Za-z0-9_.-]+', '_', s)
    s = s.strip('_.')
    return s or 'unknown'


def upload_product_featured_image(instance, filename):
    product = instance
    vendor_code = ''
    if product.vendor and getattr(product.vendor, 'vendor_code', None):
        vendor_code = product.vendor.vendor_code
    else:
        vendor_code = 'site'
    cat = _seg(getattr(product.category, 'name', '') if product.category_id else '')
    pname = _seg(product.name)
    bname = _seg(product.brand)
    base_dir = f"vendors/{vendor_code}/{cat}/{pname}/{bname}"
    name, ext = os.path.splitext(filename)
    ext = (ext or '.jpg').lower()
    return f"{base_dir}/featured{ext}"


def upload_product_gallery_image(instance, filename):
    product = instance.product
    vendor_code = ''
    if product.vendor and getattr(product.vendor, 'vendor_code', None):
        vendor_code = product.vendor.vendor_code
    else:
        vendor_code = 'site'
    cat = _seg(getattr(product.category, 'name', '') if product.category_id else '')
    pname = _seg(product.name)
    bname = _seg(product.brand)
    base_dir = f"vendors/{vendor_code}/{cat}/{pname}/{bname}"
    name, ext = os.path.splitext(filename)
    ext = (ext or '.jpg').lower()
    idx = (product.images.count() or 0) + 1
    return f"{base_dir}/{idx:03d}{ext}"


class ProductImage(models.Model):
    """Additional Product Images"""
    
    product = models.ForeignKey(
        Product,
        on_delete=models.CASCADE,
        related_name='images'
    )
    image = models.ImageField(upload_to=upload_product_gallery_image)
    # thumbnail = ImageSpecField(  # Not installed yet
    #     source='image',
    #     processors=[ResizeToFill(300, 300)],
    #     format='JPEG',
    #     options={'quality': 85}
    # )
    alt_text = models.CharField(max_length=200, blank=True)
    order = models.IntegerField(default=0)
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        ordering = ['order', '-created_at']
    
    def __str__(self):
        return f"{self.product.name} - Image {self.id}"


class ProductVariation(models.Model):
    """Product Variations (Size, Color, etc.)"""
    
    product = models.ForeignKey(
        Product,
        on_delete=models.CASCADE,
        related_name='variations'
    )
    name = models.CharField(max_length=100, help_text="e.g., Size, Color")
    value = models.CharField(max_length=100, help_text="e.g., Large, Red")
    price_adjustment = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=0,
        help_text="Additional price for this variation"
    )
    stock = models.IntegerField(default=0)
    sku_suffix = models.CharField(max_length=50, blank=True, verbose_name='Product Code Suffix')
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    length = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    width = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    height = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    DIMENSION_UNIT_CHOICES = [
        ('mm', 'Millimeter'),
        ('cm', 'Centimeter'),
        ('m', 'Meter'),
        ('in', 'Inch'),
        ('ft', 'Foot'),
    ]
    dimension_unit = models.CharField(max_length=10, choices=DIMENSION_UNIT_CHOICES, default='cm')
    quantity_value = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    QUANTITY_UNIT_CHOICES = [
        ('pcs', 'Pieces'),
        ('pair', 'Pair'),
        ('set', 'Set'),
        ('mm', 'Millimeter'),
        ('cm', 'Centimeter'),
        ('m', 'Meter'),
    ]
    quantity_unit = models.CharField(max_length=10, choices=QUANTITY_UNIT_CHOICES, default='pcs')
    
    class Meta:
        unique_together = ('product', 'name', 'value')
        ordering = ['name', 'value']
    
    def __str__(self):
        return f"{self.product.name} - {self.name}: {self.value}"
    
    @property
    def full_sku(self):
        """Returns full product code with variation suffix"""
        return f"{self.product.sku}-{self.sku_suffix}" if self.sku_suffix else self.product.sku


class Review(models.Model):
    """Product Reviews and Ratings"""
    
    product = models.ForeignKey(
        Product,
        on_delete=models.CASCADE,
        related_name='reviews'
    )
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='reviews'
    )
    rating = models.IntegerField(
        validators=[MinValueValidator(1), MaxValueValidator(5)]
    )
    title = models.CharField(max_length=200, blank=True)
    comment = models.TextField()
    
    # Moderation
    is_approved = models.BooleanField(default=True)
    is_verified_purchase = models.BooleanField(default=False)
    
    # Helpful votes
    helpful_count = models.IntegerField(default=0)
    
    # Timestamps
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        unique_together = ('product', 'user')
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['product', '-created_at']),
        ]
    
    def __str__(self):
        return f"{self.user.email} - {self.product.name} - {self.rating}★"
