"""
Модели для комплектов (ProductKit) и их компонентов.
Цена комплекта динамически вычисляется из actual_price компонентов.
"""
from decimal import Decimal
from django.db import models
from django.db.models import Q
from django.utils import timezone
from django.core.exceptions import ValidationError

from .base import BaseProductEntity
from .categories import ProductCategory, ProductTag
from .variants import ProductVariantGroup
from .products import Product
from ..utils.sku_generator import generate_kit_sku


class ProductKit(BaseProductEntity):
    """
    Шаблон комплекта / букета (рецепт).
    Наследует общие поля из BaseProductEntity.

    Цена комплекта = сумма actual_price всех компонентов + корректировка.
    Корректировка может быть увеличением или уменьшением на % или фиксированную сумму.
    """
    ADJUSTMENT_TYPE_CHOICES = [
        ('none', 'Без изменения'),
        ('increase_percent', 'Увеличить на %'),
        ('increase_amount', 'Увеличить на сумму'),
        ('decrease_percent', 'Уменьшить на %'),
        ('decrease_amount', 'Уменьшить на сумму'),
    ]

    # Categories and Tags
    categories = models.ManyToManyField(
        ProductCategory,
        blank=True,
        related_name='kits',
        verbose_name="Категории"
    )
    tags = models.ManyToManyField(
        ProductTag,
        blank=True,
        related_name='kits',
        verbose_name="Теги"
    )

    # ЦЕНООБРАЗОВАНИЕ - новый подход
    base_price = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=0,
        verbose_name="Базовая цена",
        help_text="Сумма actual_price всех компонентов. Пересчитывается автоматически."
    )

    price = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=0,
        verbose_name="Итоговая цена",
        help_text="Базовая цена с учетом корректировок. Вычисляется автоматически."
    )

    sale_price = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        null=True,
        blank=True,
        verbose_name="Цена со скидкой",
        help_text="Если задана, комплект продается по этой цене"
    )

    price_adjustment_type = models.CharField(
        max_length=20,
        choices=ADJUSTMENT_TYPE_CHOICES,
        default='none',
        verbose_name="Тип корректировки цены"
    )

    price_adjustment_value = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=0,
        verbose_name="Значение корректировки",
        help_text="Процент (%) или сумма (руб) в зависимости от типа корректировки"
    )

    # Временные комплекты
    is_temporary = models.BooleanField(
        default=False,
        verbose_name="Временный комплект",
        help_text="Временные комплекты не показываются в каталоге и создаются для конкретного заказа"
    )

    # Showcase creation date - editable date for when the bouquet was put on display
    showcase_created_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name="Дата размещения на витрине",
        help_text="Дата создания букета для витрины (редактируемая)"
    )

    order = models.ForeignKey(
        'orders.Order',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='temporary_kits',
        verbose_name="Заказ",
        help_text="Заказ, для которого создан временный комплект"
    )

    showcase = models.ForeignKey(
        'inventory.Showcase',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='temporary_kits',
        verbose_name="Витрина",
        help_text="Витрина, на которой выложен временный комплект"
    )

    class Meta:
        verbose_name = "Комплект"
        verbose_name_plural = "Комплекты"
        indexes = [
            models.Index(fields=['is_temporary']),
            models.Index(fields=['order']),
            models.Index(fields=['showcase']),
        ]
        constraints = [
            # Уникальное имя для активных комплектов (исключаем архивированные и снятые)
            # Примечание: временные комплекты могут иметь дубли имён (создаются для заказов)
            models.UniqueConstraint(
                fields=['name'],
                condition=Q(status='active', is_temporary=False),
                name='unique_active_kit_name'
            ),
        ]

    @property
    def actual_price(self):
        """
        Финальная цена для продажи.
        Приоритет: sale_price > price (рассчитанная)
        """
        if self.sale_price:
            return self.sale_price
        return self.price

    @property
    def main_photo(self):
        """
        Главное фото комплекта (is_main=True).
        Используется в карточках, каталоге, превью.
        
        Returns:
            ProductKitPhoto | None: Главное фото или None если фото нет
        """
        return self.photos.filter(is_main=True).first()

    def recalculate_base_price(self):
        """
        Пересчитать сумму actual_price всех компонентов.
        Вызывается автоматически при изменении цены товара (через signal).
        """
        if not self.pk:
            return  # Новый объект еще не сохранен

        total = Decimal('0')
        for item in self.kit_items.all():
            qty = item.quantity or Decimal('1')
            if item.sales_unit:
                # Для sales_unit используем цену единицы продажи
                unit_price = item.sales_unit.actual_price or Decimal('0')
                total += unit_price * qty
            elif item.product:
                # Используем зафиксированную цену если есть, иначе актуальную цену товара
                if item.unit_price is not None:
                    unit_price = item.unit_price
                else:
                    unit_price = item.product.actual_price or Decimal('0')
                total += unit_price * qty
            elif item.variant_group:
                # Для variant_group unit_price не используется (только для продуктов)
                actual_price = item.variant_group.price or Decimal('0')
                total += actual_price * qty

        self.base_price = total
        # Обновляем финальную цену
        self.price = self.calculate_final_price()
        self.save(update_fields=['base_price', 'price'])

    def calculate_final_price(self):
        """
        Вычислить финальную цену с учетом корректировок.

        Returns:
            Decimal: Итоговая цена комплекта
        """
        if self.price_adjustment_type == 'none':
            return self.base_price

        adjustment_value = self.price_adjustment_value or Decimal('0')

        if 'percent' in self.price_adjustment_type:
            adjustment = self.base_price * adjustment_value / Decimal('100')
        else:  # 'amount'
            adjustment = adjustment_value

        if 'increase' in self.price_adjustment_type:
            return self.base_price + adjustment
        else:  # 'decrease'
            return max(Decimal('0'), self.base_price - adjustment)

    def save(self, *args, **kwargs):
        """При сохранении - пересчитываем финальную цену"""
        # Генерация артикула для новых комплектов
        if not self.sku:
            self.sku = generate_kit_sku()

        # Если объект уже существует и имеет компоненты, пересчитываем base_price
        if self.pk and self.kit_items.exists():
            # Пересчитаем базовую цену из компонентов
            total = Decimal('0')
            for item in self.kit_items.all():
                if item.sales_unit:
                    actual_price = item.sales_unit.actual_price or Decimal('0')
                    qty = item.quantity or Decimal('1')
                    total += actual_price * qty
                elif item.product:
                    # Используем зафиксированную цену (unit_price) если задана, иначе актуальную цену товара
                    if item.unit_price is not None:
                        actual_price = item.unit_price
                    else:
                        actual_price = item.product.actual_price or Decimal('0')
                    qty = item.quantity or Decimal('1')
                    total += actual_price * qty
                elif item.variant_group:
                    actual_price = item.variant_group.price or Decimal('0')
                    qty = item.quantity or Decimal('1')
                    total += actual_price * qty
            self.base_price = total

        # Устанавливаем финальную цену в поле price
        self.price = self.calculate_final_price()

        # Вызов родительского save (генерация slug и т.д.)
        super().save(*args, **kwargs)

    def get_total_components_count(self):
        """Возвращает количество компонентов (строк) в комплекте"""
        return self.kit_items.count()

    def get_components_with_variants_count(self):
        """Возвращает количество компонентов, которые используют группы вариантов"""
        return self.kit_items.filter(variant_group__isnull=False).count()

    def check_availability(self, stock_manager=None):
        """
        Проверяет доступность всего комплекта (возвращает True/False).
        Для обратной совместимости. Использует calculate_available_quantity().
        """
        return self.calculate_available_quantity() > 0

    def calculate_available_quantity(self, warehouse=None):
        """
        Рассчитывает максимальное количество комплектов, которое можно собрать
        на основе свободных остатков компонентов на складе.

        Args:
            warehouse: Склад для проверки остатков. Если None, суммируются остатки по всем складам.

        Returns:
            Decimal: Максимальное количество комплектов (0 если хоть один компонент недоступен)
        """
        from inventory.models import Stock

        if not self.kit_items.exists():
            return Decimal('0')

        min_available = None

        for kit_item in self.kit_items.select_related('product', 'variant_group'):
            # Определяем товар для проверки
            product = None
            if kit_item.product:
                product = kit_item.product
            elif kit_item.variant_group:
                # Берём первый активный товар из группы вариантов
                available_products = kit_item.get_available_products()
                product = available_products[0] if available_products else None

            if not product:
                # Если товар не найден - комплект недоступен
                return Decimal('0')

            # Получаем остатки на складе
            stock_filter = {'product': product}
            if warehouse:
                stock_filter['warehouse'] = warehouse

            stocks = Stock.objects.filter(**stock_filter)

            # Суммируем свободное количество (available - reserved)
            total_free = Decimal('0')
            for stock in stocks:
                free_qty = stock.quantity_available - stock.quantity_reserved
                total_free += free_qty

            # Вычисляем сколько комплектов можно собрать из этого компонента
            component_quantity = kit_item.quantity or Decimal('1')
            if component_quantity <= 0:
                return Decimal('0')

            kits_from_this_component = total_free / component_quantity

            # Ищем минимум (узкое место)
            if min_available is None or kits_from_this_component < min_available:
                min_available = kits_from_this_component

        # Возвращаем целую часть (нельзя собрать половину комплекта)
        # Нельзя собрать отрицательное количество комплектов
        if min_available is not None:
            if min_available <= 0:
                return Decimal('0')
            return Decimal(int(min_available))
        return Decimal('0')

    def make_permanent(self):
        """
        Преобразует временный комплект в постоянный.
        Отвязывает от заказа и делает видимым в каталоге.

        Returns:
            bool: True если преобразование успешно, False если комплект уже постоянный
        """
        if not self.is_temporary:
            return False

        self.is_temporary = False
        self.order = None
        self.save(update_fields=['is_temporary', 'order'])
        return True

    def create_snapshot(self):
        """
        Создает снимок текущего состояния комплекта.
        Используется при добавлении комплекта в заказ для сохранения истории.

        Returns:
            KitSnapshot: Созданный снимок с компонентами
        """
        from orders.models import KitSnapshot, KitItemSnapshot

        # Создаем снимок комплекта
        snapshot = KitSnapshot.objects.create(
            original_kit=self,
            name=self.name,
            sku=self.sku or '',
            description=self.description or '',
            base_price=self.base_price,
            price=self.price,
            sale_price=self.sale_price,
            price_adjustment_type=self.price_adjustment_type,
            price_adjustment_value=self.price_adjustment_value,
            is_temporary=self.is_temporary,
        )

        # Создаем снимки компонентов
        for item in self.kit_items.select_related('product', 'variant_group'):
            product_price = Decimal('0')
            if item.product:
                product_price = item.product.actual_price or Decimal('0')
            elif item.variant_group:
                product_price = item.variant_group.price or Decimal('0')

            KitItemSnapshot.objects.create(
                kit_snapshot=snapshot,
                original_product=item.product,  # Сохраняем ссылку для резервирования
                product_name=item.product.name if item.product else '',
                product_sku=item.product.sku if item.product else '',
                product_price=product_price,
                variant_group_name=item.variant_group.name if item.variant_group else '',
                original_sales_unit=item.sales_unit,
                conversion_factor=item.sales_unit.conversion_factor if item.sales_unit else None,
                quantity=item.quantity or Decimal('1'),
            )

        return snapshot


class KitItem(models.Model):
    """
    Состав комплекта: связь между ProductKit и Product, ProductVariantGroup или ProductSalesUnit.
    Позиция может быть либо конкретным товаром, либо группой вариантов, либо конкретной единицей продажи.
    """
    kit = models.ForeignKey(ProductKit, on_delete=models.CASCADE, related_name='kit_items',
                           verbose_name="Комплект")
    product = models.ForeignKey(
        Product,
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='kit_items_direct',
        verbose_name="Конкретный товар"
    )
    variant_group = models.ForeignKey(
        ProductVariantGroup,
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='kit_items',
        verbose_name="Группа вариантов"
    )
    sales_unit = models.ForeignKey(
        'ProductSalesUnit',
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='kit_items',
        verbose_name="Единица продажи"
    )
    quantity = models.DecimalField(max_digits=10, decimal_places=3, null=True, blank=True, verbose_name="Количество")
    unit_price = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        null=True,
        blank=True,
        verbose_name="Цена за единицу (зафиксированная)",
        help_text="Если задана, используется эта цена вместо актуальной цены товара. Применяется для временных витринных комплектов."
    )

    class Meta:
        verbose_name = "Компонент комплекта"
        verbose_name_plural = "Компоненты комплектов"
        indexes = [
            models.Index(fields=['kit']),
            models.Index(fields=['product']),
            models.Index(fields=['variant_group']),
            models.Index(fields=['kit', 'product']),
            models.Index(fields=['kit', 'variant_group']),
        ]

    def __str__(self):
        return f"{self.kit.name} - {self.get_display_name()}"

    def clean(self):
        """Валидация: должна быть указана группа вариантов ИЛИ (товар [плюс опционально единица продажи])"""
        
        has_variant = bool(self.variant_group)
        has_product = bool(self.product)
        has_sales_unit = bool(self.sales_unit)

        # 1. Проверка на пустоту
        if not (has_variant or has_product or has_sales_unit):
            raise ValidationError(
                "Необходимо указать либо товар, либо группу вариантов."
            )

        # 2. Несовместимость: Группа вариантов VS Товар/Единица
        if has_variant and (has_product or has_sales_unit):
             raise ValidationError(
                "Нельзя указывать группу вариантов одновременно с товаром или единицей продажи."
            )

        # 3. Зависимость: Если есть sales_unit, должен быть product
        if has_sales_unit and not has_product:
             raise ValidationError(
                "Если указана единица продажи, должен быть выбран соответствующий товар."
             )
        
        # 4. Проверка принадлежности
        if has_sales_unit and has_product and self.sales_unit.product != self.product:
            raise ValidationError(
                "Выбранная единица продажи не принадлежит указанному товару."
            )

    def get_display_name(self):
        """Возвращает строку для отображения названия компонента"""
        # Приоритет: сначала единица продажи, затем товар, затем группа вариантов
        if self.sales_unit:
            return f"[Единица продажи] {self.sales_unit.name}"
        elif self.product:
            return self.product.name
        elif self.variant_group:
            return f"[Варианты] {self.variant_group.name}"
        return "Не указан"

    def has_priorities_set(self):
        """Проверяет, настроены ли приоритеты замены для данного компонента"""
        return self.priorities.exists()

    def get_available_products(self):
        """
        Возвращает список доступных товаров для этого компонента.

        Если указана единица продажи - возвращает товар, к которому она относится.
        Если указан конкретный товар - возвращает его.
        Если указаны приоритеты - возвращает товары в порядке приоритета.
        Если не указаны приоритеты - возвращает все активные товары из группы вариантов.
        """
        # Приоритет: сначала единица продажи, затем товар, затем группа вариантов
        if self.sales_unit:
            # Если указана единица продажи, возвращаем товар, к которому она относится
            return [self.sales_unit.product]

        if self.product:
            # Если указан конкретный товар, возвращаем только его
            return [self.product]

        if self.variant_group:
            # Если есть настроенные приоритеты, используем их
            if self.has_priorities_set():
                return [
                    priority.product
                    for priority in self.priorities.select_related('product').order_by('priority', 'id')
                ]
            # Иначе возвращаем все товары из группы
            return list(self.variant_group.products.filter(status='active'))

        return []

    def get_best_available_product(self, stock_manager=None):
        """
        Возвращает первый доступный товар по приоритету, соответствующий требованиям по количеству.
        """
        from ..utils.stock_manager import StockManager

        if stock_manager is None:
            stock_manager = StockManager()

        available_products = self.get_available_products()

        for product in available_products:
            if stock_manager.check_stock(product, self.quantity):
                return product

        return None


class KitItemPriority(models.Model):
    """
    Приоритеты товаров для конкретной позиции букета.
    Позволяет настроить индивидуальные приоритеты замен для каждого букета.
    """
    kit_item = models.ForeignKey(
        KitItem,
        on_delete=models.CASCADE,
        related_name='priorities',
        verbose_name="Позиция в букете"
    )
    product = models.ForeignKey(
        Product,
        on_delete=models.CASCADE,
        verbose_name="Товар"
    )
    priority = models.PositiveIntegerField(
        default=0,
        help_text="Меньше = выше приоритет (0 - наивысший)"
    )

    class Meta:
        verbose_name = "Приоритет варианта"
        verbose_name_plural = "Приоритеты вариантов"
        ordering = ['priority', 'id']
        unique_together = ['kit_item', 'product']

    def __str__(self):
        return f"{self.product.name} (приоритет {self.priority})"


class ConfigurableProduct(BaseProductEntity):
    """
    Вариативный товар, объединяющий несколько ProductKit или Product
    как варианты для внешних площадок (WooCommerce и подобные).

    Примеры использования:
    - Роза Фридом с вариантами длины стебля (50, 60, 70 см) — варианты это Product
    - Букет "Нежность" с вариантами количества роз (15, 25, 51) — варианты это ProductKit
    """
    class Meta:
        verbose_name = "Вариативный товар"
        verbose_name_plural = "Вариативные товары"
        # Уникальность активного имени наследуется из BaseProductEntity

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        """При сохранении - генерируем артикул если не задан"""
        # Генерация артикула для новых вариативных товаров
        if not self.sku:
            from ..utils.sku_generator import generate_configurable_sku
            self.sku = generate_configurable_sku()

        # Вызов родительского save (генерация slug и т.д.)
        super().save(*args, **kwargs)

    def delete(self, *args, **kwargs):
        """
        Физическое удаление вариативного товара из БД.
        При удалении удаляются только связи (ConfigurableProductOption),
        но сами ProductKit/Product остаются нетронутыми благодаря CASCADE на уровне связей.
        """
        # Используем super() для вызова стандартного Django delete, минуя BaseProductEntity.delete()
        super(BaseProductEntity, self).delete(*args, **kwargs)


class ConfigurableProductAttribute(models.Model):
    """
    Атрибут родительского вариативного товара с привязкой к ProductKit или Product.

    Каждое значение атрибута может быть связано с ProductKit или Product.
    Например:
    - Длина: 50 → Product (Роза 50см)
    - Длина: 60 → Product (Роза 60см)
    - Количество: 15 роз → ProductKit (Букет 15 роз)
    """
    parent = models.ForeignKey(
        'ConfigurableProduct',
        on_delete=models.CASCADE,
        related_name='parent_attributes',
        verbose_name="Родительский товар"
    )
    name = models.CharField(
        max_length=150,
        verbose_name="Название атрибута",
        help_text="Например: Цвет, Размер, Длина"
    )
    option = models.CharField(
        max_length=150,
        verbose_name="Значение опции",
        help_text="Например: Красный, M, 60см"
    )
    # Один из двух должен быть заполнен (kit XOR product) или оба пустые
    kit = models.ForeignKey(
        ProductKit,
        on_delete=models.CASCADE,
        related_name='as_attribute_value_in',
        verbose_name="Комплект для этого значения",
        help_text="Какой ProductKit связан с этим значением атрибута",
        blank=True,
        null=True
    )
    product = models.ForeignKey(
        'Product',
        on_delete=models.CASCADE,
        related_name='as_attribute_value_in',
        verbose_name="Товар для этого значения",
        help_text="Какой Product связан с этим значением атрибута",
        blank=True,
        null=True
    )
    position = models.PositiveIntegerField(
        default=0,
        verbose_name="Порядок отображения",
        help_text="Меньше = выше в списке"
    )
    visible = models.BooleanField(
        default=True,
        verbose_name="Видимый на витрине",
        help_text="Показывать ли атрибут на странице товара"
    )

    class Meta:
        verbose_name = "Атрибут вариативного товара"
        verbose_name_plural = "Атрибуты вариативных товаров"
        ordering = ['parent', 'position', 'name', 'option']
        indexes = [
            models.Index(fields=['parent', 'name']),
            models.Index(fields=['parent', 'position']),
            models.Index(fields=['kit']),
            models.Index(fields=['product']),
        ]

    def __str__(self):
        variant_str = self.kit.name if self.kit else (self.product.name if self.product else "no variant")
        return f"{self.parent.name} - {self.name}: {self.option} ({variant_str})"

    @property
    def variant(self):
        """Возвращает связанный вариант (kit или product)"""
        return self.kit or self.product

    @property
    def variant_type(self):
        """Тип варианта: 'kit', 'product' или None"""
        if self.kit:
            return 'kit'
        elif self.product:
            return 'product'
        return None


class ConfigurableProductOption(models.Model):
    """
    Отдельный вариант внутри ConfigurableProduct, указывающий на ProductKit ИЛИ Product.
    Атрибуты варианта хранятся в структурированном JSON формате.
    Пример: {"length": "60", "color": "red"}
    """
    parent = models.ForeignKey(
        'ConfigurableProduct',
        on_delete=models.CASCADE,
        related_name='options',
        verbose_name="Родитель (вариативный товар)"
    )
    # Один из двух должен быть заполнен (kit XOR product)
    kit = models.ForeignKey(
        ProductKit,
        on_delete=models.CASCADE,
        related_name='as_configurable_option_in',
        verbose_name="Комплект (вариант)",
        blank=True,
        null=True
    )
    product = models.ForeignKey(
        'Product',
        on_delete=models.CASCADE,
        related_name='as_configurable_option_in',
        verbose_name="Товар (вариант)",
        blank=True,
        null=True
    )
    attributes = models.JSONField(
        default=dict,
        blank=True,
        verbose_name="Атрибуты варианта",
        help_text='Структурированные атрибуты. Пример: {"length": "60", "color": "red"}'
    )
    is_default = models.BooleanField(
        default=False,
        verbose_name="Вариант по умолчанию"
    )
    variant_sku = models.CharField(
        max_length=50,
        blank=True,
        verbose_name="Артикул варианта",
        help_text="Дополнительный артикул для внешних площадок. Генерируется автоматически."
    )

    class Meta:
        verbose_name = "Вариант товара"
        verbose_name_plural = "Варианты товаров"
        indexes = [
            models.Index(fields=['parent']),
            models.Index(fields=['kit']),
            models.Index(fields=['product']),
            models.Index(fields=['parent', 'is_default']),
            models.Index(fields=['variant_sku']),
        ]
        constraints = [
            # kit XOR product — один из двух должен быть заполнен
            models.CheckConstraint(
                check=(
                    models.Q(kit__isnull=False, product__isnull=True) |
                    models.Q(kit__isnull=True, product__isnull=False)
                ),
                name='configurable_option_kit_xor_product'
            ),
        ]

    def __str__(self):
        variant_name = self.kit.name if self.kit else (self.product.name if self.product else "N/A")
        return f"{self.parent.name} → {variant_name}"

    def save(self, *args, **kwargs):
        """При создании - генерируем variant_sku если не задан"""
        if not self.variant_sku and self.parent_id:
            # Генерируем артикул варианта
            self.variant_sku = self._generate_variant_sku()
        
        super().save(*args, **kwargs)

    def _generate_variant_sku(self):
        """
        Генерирует артикул варианта в формате {parent.sku}-V{counter}.
        Счетчик не переиспользуется при удалении вариантов (защита интеграций).
        """
        import re
        
        # Получаем все варианты родителя с заполненным variant_sku
        existing_variants = ConfigurableProductOption.objects.filter(
            parent=self.parent,
            variant_sku__isnull=False
        ).exclude(pk=self.pk).values_list('variant_sku', flat=True)
        
        # Извлекаем номера из существующих variant_sku
        max_number = 0
        for sku in existing_variants:
            # Ищем паттерн -V\d+ в конце строки
            match = re.search(r'-V(\d+)$', sku)
            if match:
                number = int(match.group(1))
                max_number = max(max_number, number)
        
        # Следующий номер
        next_number = max_number + 1
        
        # Формируем артикул
        return f"{self.parent.sku}-V{next_number}"

    @property
    def variant(self):
        """Возвращает связанный вариант (kit или product)"""
        return self.kit or self.product

    @property
    def variant_type(self):
        """Тип варианта: 'kit' или 'product'"""
        return 'kit' if self.kit else 'product'

    @property
    def variant_name(self):
        """Название варианта"""
        return self.variant.name if self.variant else None

    @property
    def variant_base_sku(self):
        """Основной SKU варианта (Product/ProductKit)"""
        return self.variant.sku if self.variant else None

    @property
    def variant_price(self):
        """Цена варианта"""
        if self.kit:
            return self.kit.actual_price
        elif self.product:
            return self.product.sale_price or self.product.price
        return None


class ConfigurableProductOptionAttribute(models.Model):
    """
    Связь между вариантом (ConfigurableProductOption) и
    конкретным значением атрибута (ConfigurableProductAttribute).

    Вместо хранения текстового поля attributes в ConfigurableProductOption,
    мы создаем явные связи между вариантом и выбранными значениями атрибутов.

    Пример:
    - option: ConfigurableProductOption (вариант "15 роз 60см")
    - attribute: ConfigurableProductAttribute (Длина: 60)
    """
    option = models.ForeignKey(
        'ConfigurableProductOption',
        on_delete=models.CASCADE,
        related_name='attributes_set',
        verbose_name="Вариант"
    )
    attribute = models.ForeignKey(
        'ConfigurableProductAttribute',
        on_delete=models.CASCADE,
        verbose_name="Значение атрибута"
    )

    class Meta:
        verbose_name = "Атрибут варианта"
        verbose_name_plural = "Атрибуты варианта"
        # Одна опция не может использовать два разных значения одного атрибута
        # Например: нельзя иметь Длина=60 и Длина=70 одновременно
        # Уникальность будет проверяться на уровне формы
        unique_together = [['option', 'attribute']]
        indexes = [
            models.Index(fields=['option']),
            models.Index(fields=['attribute']),
        ]

    def __str__(self):
        return f"{self.option.parent.name} → {self.attribute.name}: {self.attribute.option}"
