from django.db import models
from django.core.exceptions import ValidationError


class BaseDiscount(models.Model):
    """
    Абстрактный базовый класс для всех типов скидок.
    Содержит общие поля и логику валидации.
    """
    DISCOUNT_TYPE_CHOICES = [
        ('percentage', 'Процент'),
        ('fixed_amount', 'Фиксированная сумма'),
    ]

    SCOPE_CHOICES = [
        ('order', 'На весь заказ'),
        ('product', 'На товар'),
        ('category', 'На категорию товаров'),
    ]

    COMBINE_MODE_CHOICES = [
        ('stack', 'Складывать (суммировать)'),
        ('max_only', 'Только максимум'),
        ('exclusive', 'Исключающая (отменяет остальные)'),
    ]

    name = models.CharField(
        max_length=200,
        verbose_name="Название скидки"
    )

    description = models.TextField(
        blank=True,
        verbose_name="Описание"
    )

    discount_type = models.CharField(
        max_length=20,
        choices=DISCOUNT_TYPE_CHOICES,
        verbose_name="Тип скидки"
    )

    value = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        verbose_name="Значение",
        help_text="Процент (0-100) или сумма в рублях"
    )

    scope = models.CharField(
        max_length=20,
        choices=SCOPE_CHOICES,
        default='order',
        verbose_name="Уровень применения"
    )

    is_active = models.BooleanField(
        default=True,
        verbose_name="Активна",
        db_index=True
    )

    start_date = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name="Дата начала действия"
    )

    end_date = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name="Дата окончания действия"
    )

    max_usage_count = models.PositiveIntegerField(
        null=True,
        blank=True,
        verbose_name="Макс. количество использований",
        help_text="Оставьте пустым для безлимитного использования"
    )

    current_usage_count = models.PositiveIntegerField(
        default=0,
        verbose_name="Текущее количество использований"
    )

    priority = models.PositiveIntegerField(
        default=0,
        verbose_name="Приоритет",
        help_text="Более высокий приоритет применяется первым"
    )

    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name="Дата создания"
    )

    created_by = models.ForeignKey(
        'accounts.CustomUser',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='created_discounts',
        verbose_name="Создал"
    )

    class Meta:
        abstract = True
        ordering = ['-priority', '-created_at']
        indexes = [
            models.Index(fields=['is_active']),
            models.Index(fields=['scope']),
            models.Index(fields=['discount_type']),
        ]

    def __str__(self):
        if self.discount_type == 'percentage':
            return f"{self.name} ({self.value}%)"
        return f"{self.name} (-{self.value} руб.)"

    def clean(self):
        """Валидация значений скидки"""
        if self.discount_type == 'percentage':
            if self.value < 0 or self.value > 100:
                raise ValidationError({
                    'value': 'Процентная скидка должна быть от 0 до 100'
                })
        elif self.discount_type == 'fixed_amount':
            if self.value < 0:
                raise ValidationError({
                    'value': 'Фиксированная скидка не может быть отрицательной'
                })

        if self.start_date and self.end_date and self.start_date > self.end_date:
            raise ValidationError({
                'end_date': 'Дата окончания не может быть раньше даты начала'
            })

    def calculate_discount_amount(self, base_amount):
        """
        Вычислить сумму скидки для заданной базовой суммы.

        Args:
            base_amount: Десятичное число - базовая сумма

        Returns:
            Decimal: Сумма скидки (не может превышать base_amount)
        """
        if self.discount_type == 'percentage':
            return base_amount * self.value / 100
        else:  # fixed_amount
            return min(self.value, base_amount)  # Скидка не может превышать сумму

    def is_valid_now(self):
        """
        Проверить, что скидка активна в текущий момент времени.

        Returns:
            bool: True если скидка активна
        """
        from django.utils import timezone

        if not self.is_active:
            return False

        now = timezone.now()

        if self.start_date and now < self.start_date:
            return False

        if self.end_date and now > self.end_date:
            return False

        if self.max_usage_count and self.current_usage_count >= self.max_usage_count:
            return False

        return True
