from decimal import Decimal
from django.db import models
from django.core.exceptions import ValidationError
from products.models import Product, ProductKit
from .order import Order
from .kit_snapshot import KitSnapshot


class OrderItem(models.Model):
    """
    Позиция (товар) в заказе.
    Хранит информацию о товаре или комплекте, количестве и цене на момент заказа.
    """
    order = models.ForeignKey(
        Order,
        on_delete=models.CASCADE,
        related_name='items',
        verbose_name="Заказ"
    )

    # Товар или комплект (один из двух должен быть заполнен)
    product = models.ForeignKey(
        Product,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        related_name='order_items',
        verbose_name="Товар"
    )

    product_kit = models.ForeignKey(
        ProductKit,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        related_name='order_items',
        verbose_name="Комплект товаров"
    )

    # Снимок комплекта (для сохранения истории состава комплекта на момент заказа)
    kit_snapshot = models.ForeignKey(
        KitSnapshot,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='order_items',
        verbose_name="Снимок комплекта",
        help_text="Хранит состав комплекта на момент оформления заказа"
    )

    # Снапшот названия и артикула (для Product и Kit)
    item_name_snapshot = models.CharField(
        max_length=200,
        default='',
        verbose_name="Название на момент заказа"
    )

    item_sku_snapshot = models.CharField(
        max_length=100,
        blank=True,
        verbose_name="Артикул на момент заказа"
    )

    quantity = models.DecimalField(
        max_digits=10,
        decimal_places=3,
        default=1,
        verbose_name="Количество",
        help_text="Количество в единицах продажи (может быть дробным)"
    )

    price = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        verbose_name="Цена за единицу",
        help_text="Цена на момент создания заказа (фиксируется)"
    )

    is_custom_price = models.BooleanField(
        default=False,
        verbose_name="Цена изменена вручную",
        help_text="True если цена была изменена вручную при создании заказа"
    )

    # === СКИДКИ ===
    # Скидки хранятся в модели DiscountApplication (через related_name='discount_applications')
    # Старые поля applied_discount, discount_amount УДАЛЕНЫ
    # Используйте свойства ниже для доступа к скидкам

    # Витринные продажи
    is_from_showcase = models.BooleanField(
        default=False,
        verbose_name="С витрины",
        help_text="True если товар продан с витрины"
    )

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

    # === ПОЛЯ ДЛЯ ЕДИНИЦ ПРОДАЖИ ===
    sales_unit = models.ForeignKey(
        'products.ProductSalesUnit',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='order_items',
        verbose_name="Единица продажи"
    )
    unit_name_snapshot = models.CharField(
        max_length=100,
        blank=True,
        default='',
        verbose_name="Название единицы (snapshot)",
        help_text="Название единицы продажи на момент заказа"
    )
    conversion_factor_snapshot = models.DecimalField(
        max_digits=15,
        decimal_places=6,
        null=True,
        blank=True,
        verbose_name="Коэффициент конверсии (snapshot)",
        help_text="Коэффициент конверсии на момент заказа"
    )
    quantity_in_base_units = models.DecimalField(
        max_digits=10,
        decimal_places=6,
        null=True,
        blank=True,
        verbose_name="Количество в базовых единицах",
        help_text="Количество в единицах хранения товара (для списания со склада)"
    )

    # Временные метки
    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name="Дата добавления"
    )

    # TODO: История изменений (simple_history) - вернуть позже
    # history = HistoricalRecords()

    class Meta:
        verbose_name = "Позиция заказа"
        verbose_name_plural = "Позиции заказа"
        indexes = [
            models.Index(fields=['order']),
            models.Index(fields=['product']),
            models.Index(fields=['product_kit']),
            models.Index(fields=['is_from_showcase']),
            models.Index(fields=['showcase']),
        ]

    def __str__(self):
        return f"{self.item_name_snapshot} x{self.quantity} в заказе #{self.order.order_number}"

    def clean(self):
        """Валидация модели"""
        super().clean()

        # Проверка: должен быть заполнен либо product, либо product_kit
        if not self.product and not self.product_kit:
            raise ValidationError(
                'Необходимо указать либо товар, либо комплект товаров'
            )

        # Проверка: не должны быть заполнены оба поля одновременно
        if self.product and self.product_kit:
            raise ValidationError(
                'Нельзя указать одновременно и товар, и комплект'
            )

    def save(self, *args, **kwargs):
        is_new = not self.pk

        # Определяем, изменился ли комплект (для существующих записей)
        kit_changed = False
        if self.pk and self.product_kit:
            old = OrderItem.objects.filter(pk=self.pk).values('product_kit_id').first()
            if old and old['product_kit_id'] != self.product_kit_id:
                kit_changed = True

        # Создаем snapshot для комплекта (новый или при замене)
        if self.product_kit and (is_new or kit_changed):
            self.kit_snapshot = self.product_kit.create_snapshot()

        # Сохраняем название и артикул
        if self.product:
            self.item_name_snapshot = self.product.name
            self.item_sku_snapshot = self.product.sku or ''
        elif self.kit_snapshot:
            self.item_name_snapshot = self.kit_snapshot.name
            self.item_sku_snapshot = self.kit_snapshot.sku or ''

        # Автоматически фиксируем цену при создании, если она не указана
        if not self.price:
            # Сначала проверяем единицу продажи
            if self.sales_unit:
                self.price = self.sales_unit.actual_price
            elif self.product:
                self.price = self.product.actual_price
            elif self.kit_snapshot:
                self.price = self.kit_snapshot.actual_price

        # Сохраняем snapshot единицы продажи
        if self.sales_unit:
            self.unit_name_snapshot = self.sales_unit.name
            self.conversion_factor_snapshot = self.sales_unit.conversion_factor
            self.quantity_in_base_units = self.sales_unit.convert_to_base(
                Decimal(self.quantity)
            )

        super().save(*args, **kwargs)

    def get_total_price(self):
        """Возвращает общую стоимость позиции с учетом скидки"""
        subtotal = self.price * self.quantity
        discount = Decimal(str(self.discount_amount)) if self.discount_amount else Decimal('0')
        return subtotal - discount

    @property
    def item_name(self):
        """Название из snapshot"""
        return self.item_name_snapshot

    @property
    def original_price(self):
        """Оригинальная цена из snapshot"""
        if self.kit_snapshot:
            return self.kit_snapshot.actual_price
        return self.price

    @property
    def price_difference(self):
        """Разница между установленной ценой и оригинальной"""
        if self.is_custom_price and self.original_price:
            return self.price - self.original_price
        return None

    # === Свойства для доступа к скидкам (через DiscountApplication) ===

    @property
    def item_discounts(self):
        """Скидки на эту позицию (QuerySet DiscountApplication)"""
        return self.discount_applications.filter(target='order_item').select_related('discount')

    @property
    def discount_amount(self):
        """Общая сумма скидки на позицию"""
        from django.db.models import Sum
        total = self.item_discounts.aggregate(total=Sum('discount_amount'))['total']
        return total if total else Decimal('0')

    @property
    def applied_discount(self):
        """Первая применённая скидка (для обратной совместимости)"""
        first = self.item_discounts.first()
        return first.discount if first else None
