"""
Модели единиц измерения.
- UnitOfMeasure: справочник единиц измерения
- ProductSalesUnit: единицы продажи товара с коэффициентами конверсии
"""
from decimal import Decimal
from django.db import models
from django.core.validators import MinValueValidator
from django.core.exceptions import ValidationError


class UnitOfMeasure(models.Model):
    """
    Справочник единиц измерения.
    Расширяемый справочник вместо жестко заданных UNIT_CHOICES.
    """
    code = models.CharField(
        max_length=20,
        unique=True,
        verbose_name="Код",
        help_text="Короткий код: шт, кг, банч, ветка"
    )
    name = models.CharField(
        max_length=100,
        verbose_name="Название",
        help_text="Полное название: Штука, Килограмм, Банч"
    )
    short_name = models.CharField(
        max_length=10,
        verbose_name="Сокращение",
        help_text="Для UI: шт., кг., бч."
    )
    is_active = models.BooleanField(
        default=True,
        verbose_name="Активна"
    )
    position = models.PositiveIntegerField(
        default=0,
        verbose_name="Порядок сортировки"
    )

    class Meta:
        verbose_name = "Единица измерения"
        verbose_name_plural = "Единицы измерения"
        ordering = ['position', 'name']

    def __str__(self):
        return f"{self.name} ({self.code})"


class ProductSalesUnit(models.Model):
    """
    Единица продажи товара с коэффициентом конверсии.
    Один товар может иметь несколько единиц продажи.

    Пример:
        Товар: Пихта Нобилис (базовая единица: банч)
        Единицы продажи:
        - Ветка большая: 1 банч = 15 веток, цена 300₽
        - Ветка средняя: 1 банч = 30 веток, цена 150₽
        - Ветка маленькая: 1 банч = 50 веток, цена 100₽
    """
    product = models.ForeignKey(
        'Product',
        on_delete=models.CASCADE,
        related_name='sales_units',
        verbose_name="Товар"
    )
    name = models.CharField(
        max_length=100,
        verbose_name="Название",
        help_text="Например: 'Ветка большая', 'Ветка средняя'"
    )
    conversion_factor = models.DecimalField(
        max_digits=15,
        decimal_places=6,
        validators=[MinValueValidator(Decimal('0.000001'))],
        verbose_name="Коэффициент конверсии",
        help_text="Сколько единиц продажи в 1 базовой единице товара. "
                  "Например: 15 (из 1 банча получается 15 больших веток)"
    )
    price = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        validators=[MinValueValidator(Decimal('0'))],
        verbose_name="Цена продажи"
    )
    sale_price = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        null=True,
        blank=True,
        validators=[MinValueValidator(Decimal('0'))],
        verbose_name="Цена со скидкой"
    )
    min_quantity = models.DecimalField(
        max_digits=10,
        decimal_places=3,
        default=Decimal('1'),
        validators=[MinValueValidator(Decimal('0.001'))],
        verbose_name="Мин. количество",
        help_text="Минимальное количество для продажи"
    )
    quantity_step = models.DecimalField(
        max_digits=10,
        decimal_places=3,
        default=Decimal('1'),
        validators=[MinValueValidator(Decimal('0.001'))],
        verbose_name="Шаг количества",
        help_text="С каким шагом можно заказывать (0.1, 0.5, 1)"
    )
    is_default = models.BooleanField(
        default=False,
        verbose_name="Единица по умолчанию",
        help_text="Единица, выбираемая по умолчанию при добавлении в заказ"
    )
    is_active = models.BooleanField(
        default=True,
        verbose_name="Активна"
    )
    position = models.PositiveIntegerField(
        default=0,
        verbose_name="Порядок сортировки"
    )

    class Meta:
        verbose_name = "Единица продажи товара"
        verbose_name_plural = "Единицы продажи товаров"
        ordering = ['position', 'id']
        unique_together = [['product', 'name']]

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

    def clean(self):
        super().clean()
        if self.conversion_factor and self.conversion_factor <= 0:
            raise ValidationError({
                'conversion_factor': 'Коэффициент конверсии должен быть больше 0'
            })
        if self.sale_price and self.price and self.sale_price >= self.price:
            raise ValidationError({
                'sale_price': 'Цена со скидкой должна быть меньше основной цены'
            })

    def save(self, *args, **kwargs):
        # Если это единица по умолчанию, снимаем флаг с других
        if self.is_default:
            ProductSalesUnit.objects.filter(
                product=self.product,
                is_default=True
            ).exclude(pk=self.pk).update(is_default=False)
        super().save(*args, **kwargs)

    @property
    def actual_price(self):
        """Финальная цена (со скидкой или без)"""
        return self.sale_price if self.sale_price else self.price

    def convert_to_base(self, quantity):
        """
        Конвертировать количество в базовые единицы товара.

        Args:
            quantity: количество в единицах продажи

        Returns:
            Decimal: количество в базовых единицах

        Пример:
            10 больших веток → 10 / 15 = 0.667 банча
        """
        if not self.conversion_factor or self.conversion_factor == 0:
            return Decimal(quantity)
        return Decimal(quantity) / self.conversion_factor

    def convert_from_base(self, base_quantity):
        """
        Конвертировать из базовых единиц в единицы продажи.

        Args:
            base_quantity: количество в базовых единицах товара

        Returns:
            Decimal: количество в единицах продажи

        Пример:
            2.5 банча → 2.5 * 15 = 37.5 больших веток
        """
        if not self.conversion_factor:
            return Decimal(base_quantity)
        return Decimal(base_quantity) * self.conversion_factor

    def validate_quantity(self, quantity):
        """
        Проверить, что количество соответствует ограничениям.

        Args:
            quantity: количество для проверки

        Raises:
            ValidationError: если количество некорректно
        """
        quantity = Decimal(quantity)

        if quantity < self.min_quantity:
            raise ValidationError(
                f'Минимальное количество для "{self.name}": {self.min_quantity}'
            )

        # Проверяем шаг количества (с учётом погрешности float)
        if self.quantity_step and self.quantity_step > 0:
            remainder = quantity % self.quantity_step
            if remainder > Decimal('0.0001') and (self.quantity_step - remainder) > Decimal('0.0001'):
                raise ValidationError(
                    f'Количество должно быть кратно {self.quantity_step}'
                )
