"""
Валидаторы для ProductKit модели.
Извлекает логику валидации из метода clean().
"""
from decimal import Decimal
from django.core.exceptions import ValidationError
import logging

logger = logging.getLogger(__name__)


class KitValidator:
    """
    Валидатор для проверки корректности данных ProductKit.
    """

    @staticmethod
    def validate_pricing_method(kit):
        """
        Проверяет соответствие метода ценообразования заданным полям.

        Args:
            kit (ProductKit): Комплект для валидации

        Raises:
            ValidationError: Если данные не соответствуют выбранному методу ценообразования
        """
        # Проверка соответствия метода ценообразования полям
        if kit.pricing_method == 'manual' and not kit.price:
            raise ValidationError({
                'price': 'Для метода ценообразования "Ручная цена" необходимо указать цену.'
            })

        if kit.pricing_method == 'from_cost_plus_percent' and (
            kit.markup_percent is None or kit.markup_percent < 0
        ):
            raise ValidationError({
                'markup_percent': 'Для метода ценообразования "from_cost_plus_percent" необходимо указать процент наценки >= 0.'
            })

        if kit.pricing_method == 'from_cost_plus_amount' and (
            kit.markup_amount is None or kit.markup_amount < 0
        ):
            raise ValidationError({
                'markup_amount': 'Для метода ценообразования "from_cost_plus_amount" необходимо указать сумму наценки >= 0.'
            })

    @staticmethod
    def validate_sku_uniqueness(kit):
        """
        Проверяет уникальность SKU комплекта.

        Args:
            kit (ProductKit): Комплект для валидации

        Raises:
            ValidationError: Если SKU уже используется другим комплектом
        """
        if not kit.sku:
            return

        # Импортируем здесь, чтобы избежать циклических зависимостей
        from ..models.kits import ProductKit

        # Проверяем, что SKU не используется другим комплектом (если объект уже существует)
        if kit.pk:
            if ProductKit.objects.filter(sku=kit.sku).exclude(pk=kit.pk).exists():
                raise ValidationError({
                    'sku': f'Артикул "{kit.sku}" уже используется другим комплектом.'
                })
        else:
            # Для новых объектов просто проверяем, что SKU не используется
            if ProductKit.objects.filter(sku=kit.sku).exists():
                raise ValidationError({
                    'sku': f'Артикул "{kit.sku}" уже используется другим комплектом.'
                })

    @staticmethod
    def validate_pricing_method_availability(kit):
        """
        Проверяет, доступны ли методы ценообразования на основе данных себестоимости.

        Если себестоимость компонентов неполная, блокирует методы:
        - 'from_cost_plus_percent'
        - 'from_cost_plus_amount'

        И переключает на 'from_sale_prices' с предупреждением.

        Args:
            kit (ProductKit): Комплект для валидации

        Returns:
            tuple: (is_valid: bool, message: str or None)
                - is_valid: True если метод ценообразования доступен, False если был переключен
                - message: Сообщение об изменении метода ценообразования
        """
        # Методы, требующие валидной себестоимости
        restricted_methods = ['from_cost_plus_percent', 'from_cost_plus_amount']

        # Проверяем валидность себестоимости
        cost_info = kit.cost_calculation_info

        # Если себестоимость не валидна и выбран ограниченный метод
        if not cost_info['is_valid'] and kit.pricing_method in restricted_methods:
            # Переключаемся на 'from_sale_prices'
            old_method = kit.pricing_method
            kit.pricing_method = 'from_sale_prices'

            # Формируем сообщение об ошибке
            problems_text = ', '.join([
                f"{p['component_name']} — {p['reason']}"
                for p in cost_info['problems']
            ])

            message = (
                f"⚠️ Метод ценообразования был переключен с '{KitValidator._get_method_label(old_method)}' "
                f"на 'По ценам компонентов', так как не все компоненты имеют полную информацию о себестоимости. "
                f"Проблемы: {problems_text}"
            )

            logger.info(
                f"Kit {kit.name} (id={kit.pk}): pricing_method переключен с {old_method} "
                f"на from_sale_prices из-за неполной себестоимости"
            )

            return False, message

        return True, None

    @staticmethod
    def _get_method_label(method_code):
        """
        Получить человеческое описание метода ценообразования.

        Args:
            method_code (str): Код метода ценообразования

        Returns:
            str: Описание метода
        """
        method_labels = {
            'manual': 'Ручная цена',
            'from_sale_prices': 'По ценам компонентов',
            'from_cost_plus_percent': 'Себестоимость + процент',
            'from_cost_plus_amount': 'Себестоимость + фиксированная наценка'
        }
        return method_labels.get(method_code, method_code)
