"""
API представления для приложения products.
"""
from django.http import JsonResponse
from django.db import models
from django.core.cache import cache
from django.core.exceptions import ValidationError
from django.contrib.auth.decorators import login_required
import logging

from ..models import Product, ProductVariantGroup, ProductKit, ProductCategory, ProductPhoto, ProductSalesUnit

logger = logging.getLogger(__name__)


def _get_product_photo_url(product_id):
    """Получает URL главного фото товара (первого по порядку)."""
    photo = ProductPhoto.objects.filter(product_id=product_id).order_by('order').first()
    if photo and photo.image:
        return photo.image.url
    return None


def _apply_product_filters(queryset, category_id=None, tag_id=None, stock_status='all', warehouse_id=None, skip_stock_filter=False):
    """Применяет фильтры к queryset товаров.

    Args:
        stock_status: 'all' - все товары, 'in_stock' - только в наличии, 'out_of_stock' - только не в наличии
        skip_stock_filter: Если True, warehouse_id не фильтрует по остаткам.
                          Используется для приёмки товаров.
    """
    if category_id:
        queryset = queryset.filter(categories__id=category_id)
    if tag_id:
        queryset = queryset.filter(tags__id=tag_id)
    if stock_status == 'in_stock':
        queryset = queryset.filter(in_stock=True)
    elif stock_status == 'out_of_stock':
        queryset = queryset.filter(in_stock=False)
    if warehouse_id and not skip_stock_filter:
        # Фильтруем только товары, которые есть на указанном складе с доступным количеством
        # НЕ применяется при skip_stock_filter=True (приёмка товаров)
        from inventory.models import Stock
        products_with_stock = Stock.objects.filter(
            warehouse_id=warehouse_id,
            quantity_available__gt=0
        ).values_list('product_id', flat=True)
        queryset = queryset.filter(id__in=products_with_stock)
    return queryset.distinct()


def search_products_and_variants(request):
    """
    API endpoint для поиска товаров, групп вариантов и комплектов (совместимость с Select2).
    Используется для автокомплита при добавлении компонентов в комплект и товаров в заказ.

    Параметры GET:
    - q: строка поиска (term в Select2)
    - id: ID товара/комплекта для получения его данных (формат: "product_123" или "kit_456")
    - type: 'product', 'variant', 'kit' или 'all' (опционально, по умолчанию 'all')
    - page: номер страницы для пагинации (по умолчанию 1)
    - category: ID категории для фильтрации (опционально)
    - tag: ID тега для фильтрации (опционально)
    - stock_status: 'all' (все), 'in_stock' (в наличии), 'out_of_stock' (не в наличии) (опционально, по умолчанию 'all')
    - warehouse: ID склада для фильтрации только товаров с доступным остатком (опционально)

    Возвращает JSON в формате Select2 с группировкой:
    {
        "results": [
            {
                "text": "Товары",
                "children": [
                    {
                        "id": "product_1",
                        "text": "Роза красная Freedom 50см (PROD-000001)",
                        "sku": "PROD-000001",
                        "price": "150.00",
                        "actual_price": "135.00",
                        "in_stock": true,
                        "type": "product"
                    }
                ]
            },
            {
                "text": "Комплекты",
                "children": [
                    {
                        "id": "kit_1",
                        "text": "Букет 'Нежность' (KIT-000001)",
                        "sku": "KIT-000001",
                        "price": "2500.00",
                        "actual_price": "2500.00",
                        "type": "kit"
                    }
                ]
            }
        ],
        "pagination": {
            "more": false
        }
    }
    """
    # Если передан ID товара/комплекта - получаем его данные напрямую
    item_id = request.GET.get('id', '').strip()
    if item_id:
        try:
            # Проверяем формат ID: "product_123" или "kit_456" или просто "123"
            if '_' in item_id:
                item_type, numeric_id = item_id.split('_', 1)
                numeric_id = int(numeric_id)
            else:
                # Для обратной совместимости: если нет префикса, считаем что это product
                item_type = 'product'
                numeric_id = int(item_id)

            if item_type == 'product':
                product = Product.objects.prefetch_related('sales_units').get(id=numeric_id, status='active')

                # Сериализация единиц продажи
                sales_units_data = []
                for su in product.sales_units.filter(is_active=True).order_by('position', 'id'):
                    sales_units_data.append({
                        'id': su.id,
                        'name': su.name,
                        'price': str(su.price),
                        'sale_price': str(su.sale_price) if su.sale_price else None,
                        'actual_price': str(su.actual_price),
                        'conversion_factor': str(su.conversion_factor),
                        'min_quantity': str(su.min_quantity),
                        'quantity_step': str(su.quantity_step),
                        'is_default': su.is_default
                    })

                return JsonResponse({
                    'results': [{
                        'id': f'product_{product.id}',
                        'text': f"{product.name} ({product.sku})" if product.sku else product.name,
                        'sku': product.sku,
                        'price': str(product.price) if product.price else None,
                        'actual_price': str(product.actual_price) if product.actual_price else '0',
                        'in_stock': product.in_stock,
                        'type': 'product',
                        'sales_units': sales_units_data
                    }],
                    'pagination': {'more': False}
                })
            elif item_type == 'kit':
                # Для комплектов: временные комплекты можно получать по ID (для заказов)
                # но не показываем их в общем поиске
                kit = ProductKit.objects.get(id=numeric_id, status='active')
                return JsonResponse({
                    'results': [{
                        'id': f'kit_{kit.id}',
                        'text': f"{kit.name} ({kit.sku})" if kit.sku else kit.name,
                        'sku': kit.sku,
                        'price': str(kit.price) if kit.price else None,
                        'actual_price': str(kit.actual_price) if kit.actual_price else '0',
                        'type': 'kit',
                        'is_temporary': kit.is_temporary
                    }],
                    'pagination': {'more': False}
                })
            elif item_type == 'variant':
                # Для групп вариантов: получаем по ID с prefetch приоритетов
                variant = ProductVariantGroup.objects.prefetch_related(
                    'items__product'
                ).get(id=numeric_id)

                variant_price = variant.price or 0
                count = variant.items.count()

                return JsonResponse({
                    'results': [{
                        'id': variant.id,
                        'text': f"{variant.name} ({count} вариантов)",
                        'price': str(variant_price),
                        'actual_price': str(variant_price),
                        'type': 'variant',
                        'count': count
                    }],
                    'pagination': {'more': False}
                })
        except (Product.DoesNotExist, ProductKit.DoesNotExist, ProductVariantGroup.DoesNotExist, ValueError):
            return JsonResponse({'results': [], 'pagination': {'more': False}})

    query = request.GET.get('q', '').strip()
    search_type = request.GET.get('type', 'all')
    page = int(request.GET.get('page', 1))
    page_size = 30

    # Дополнительные фильтры
    category_id = request.GET.get('category', '').strip()
    tag_id = request.GET.get('tag', '').strip()
    stock_status = request.GET.get('stock_status', 'all').strip()
    warehouse_id = request.GET.get('warehouse', '').strip()
    skip_stock_filter = request.GET.get('skip_stock_filter', '').lower() == 'true'

    results = []

    # Проверяем, есть ли дополнительные фильтры
    has_filters = category_id or tag_id or stock_status != 'all' or warehouse_id

    # Если поиска нет - показываем популярные товары и комплекты
    if not query or len(query) < 2:
        # Кэшируем только если нет фильтров
        if not has_filters:
            cache_key = f'popular_items_{search_type}'
            cached_results = cache.get(cache_key)
            if cached_results:
                return JsonResponse(cached_results)

        product_results = []
        kit_results = []

        if search_type in ['all', 'product']:
            # Показываем последние добавленные активные товары
            products_qs = Product.objects.filter(status='active').prefetch_related('sales_units')
            # Применяем фильтры
            products_qs = _apply_product_filters(products_qs, category_id, tag_id, stock_status, warehouse_id, skip_stock_filter)
            products = products_qs.order_by('-created_at')[:page_size]

            for product in products:
                text = product.name
                if product.sku:
                    text += f" ({product.sku})"

                # Получаем actual_price: приоритет sale_price > price
                actual_price = product.sale_price if product.sale_price else product.price

                # Сериализация единиц продажи
                sales_units_data = []
                for su in product.sales_units.filter(is_active=True).order_by('position', 'id'):
                    sales_units_data.append({
                        'id': su.id,
                        'name': su.name,
                        'price': str(su.price),
                        'sale_price': str(su.sale_price) if su.sale_price else None,
                        'actual_price': str(su.actual_price),
                        'conversion_factor': str(su.conversion_factor),
                        'min_quantity': str(su.min_quantity),
                        'quantity_step': str(su.quantity_step),
                        'is_default': su.is_default
                    })

                product_results.append({
                    'id': f"product_{product.id}",
                    'text': text,
                    'sku': product.sku,
                    'price': str(product.price) if product.price else None,
                    'actual_price': str(actual_price) if actual_price else '0',
                    'in_stock': product.in_stock,
                    'type': 'product',
                    'photo_url': _get_product_photo_url(product.id),
                    'sales_units': sales_units_data
                })

        if search_type in ['all', 'kit']:
            # Показываем последние добавленные активные комплекты (только постоянные)
            kits = ProductKit.objects.filter(status='active', is_temporary=False)\
                .order_by('-created_at')[:page_size]\
                .values('id', 'name', 'sku', 'price', 'sale_price')

            for kit in kits:
                text = kit['name']
                if kit['sku']:
                    text += f" ({kit['sku']})"

                # Получаем actual_price: приоритет sale_price > price
                actual_price = kit['sale_price'] if kit['sale_price'] else kit['price']

                kit_results.append({
                    'id': f"kit_{kit['id']}",
                    'text': text,
                    'sku': kit['sku'],
                    'price': str(kit['price']) if kit['price'] else None,
                    'actual_price': str(actual_price) if actual_price else '0',
                    'type': 'kit'
                })

        # Формируем результат с группировкой или без
        if search_type == 'all' and (product_results or kit_results):
            # С группировкой
            grouped_results = []
            if product_results:
                grouped_results.append({
                    'text': 'Товары',
                    'children': product_results
                })
            if kit_results:
                grouped_results.append({
                    'text': 'Комплекты',
                    'children': kit_results
                })
            results = grouped_results
        else:
            # Без группировки (когда ищем только product или только kit)
            results = product_results + kit_results

        response_data = {
            'results': results,
            'pagination': {'more': False}
        }
        # Кэшируем только если нет фильтров
        if not has_filters:
            cache.set(cache_key, response_data, 3600)
        return JsonResponse(response_data)

    # Поиск товаров и комплектов (регистронезависимый поиск с приоритетом точных совпадений)
    product_results = []
    kit_results = []
    has_more = False

    # Нормализуем запрос - убираем лишние пробелы
    query_normalized = ' '.join(query.split())

    from django.db.models import Case, When, IntegerField
    from django.conf import settings

    # Поиск товаров
    if search_type in ['all', 'product']:
        # ВРЕМЕННЫЙ ФИХ для SQLite: удалить когда база данных будет PostgreSQL
        # SQLite не поддерживает регистронезависимый поиск для кириллицы в LIKE
        if 'sqlite' in settings.DATABASES['default']['ENGINE']:
            from django.db.models.functions import Lower
            query_lower = query_normalized.lower()

            products_query = Product.objects.annotate(
                name_lower=Lower('name'),
                sku_lower=Lower('sku'),
                description_lower=Lower('description')
            ).filter(
                models.Q(name_lower__contains=query_lower) |
                models.Q(sku_lower__contains=query_lower) |
                models.Q(description_lower__contains=query_lower),
                status='active'
            ).annotate(
                relevance=Case(
                    When(name_lower=query_lower, then=3),
                    When(name_lower__startswith=query_lower, then=2),
                    default=1,
                    output_field=IntegerField()
                )
            ).order_by('-relevance', 'name')
        else:
            # Основное решение для PostgreSQL (работает корректно с кириллицей)
            products_query = Product.objects.filter(
                models.Q(name__icontains=query_normalized) |
                models.Q(sku__icontains=query_normalized) |
                models.Q(description__icontains=query_normalized),
                status='active'
            ).annotate(
                relevance=Case(
                    When(name__iexact=query_normalized, then=3),
                    When(name__istartswith=query_normalized, then=2),
                    default=1,
                    output_field=IntegerField()
                )
            ).order_by('-relevance', 'name')

        # Применяем дополнительные фильтры
        products_query = _apply_product_filters(products_query, category_id, tag_id, stock_status, warehouse_id, skip_stock_filter)

        # Добавляем prefetch для единиц продажи
        products_query = products_query.prefetch_related('sales_units')

        total_products = products_query.count()
        start = (page - 1) * page_size
        end = start + page_size

        products = products_query[start:end]

        for product in products:
            text = product.name
            if product.sku:
                text += f" ({product.sku})"

            # Получаем actual_price: приоритет sale_price > price
            actual_price = product.sale_price if product.sale_price else product.price

            # Сериализация единиц продажи
            sales_units_data = []
            for su in product.sales_units.filter(is_active=True).order_by('position', 'id'):
                sales_units_data.append({
                    'id': su.id,
                    'name': su.name,
                    'price': str(su.price),
                    'sale_price': str(su.sale_price) if su.sale_price else None,
                    'actual_price': str(su.actual_price),
                    'conversion_factor': str(su.conversion_factor),
                    'min_quantity': str(su.min_quantity),
                    'quantity_step': str(su.quantity_step),
                    'is_default': su.is_default
                })

            product_results.append({
                'id': f"product_{product.id}",
                'text': text,
                'sku': product.sku,
                'price': str(product.price) if product.price else None,
                'actual_price': str(actual_price) if actual_price else '0',
                'in_stock': product.in_stock,
                'type': 'product',
                'photo_url': _get_product_photo_url(product.id),
                'sales_units': sales_units_data
            })

        has_more = total_products > end

    # Поиск комплектов
    if search_type in ['all', 'kit']:
        # Используем аналогичную логику для комплектов (только постоянные)
        if 'sqlite' in settings.DATABASES['default']['ENGINE']:
            from django.db.models.functions import Lower
            query_lower = query_normalized.lower()

            kits_query = ProductKit.objects.annotate(
                name_lower=Lower('name'),
                sku_lower=Lower('sku'),
                description_lower=Lower('description')
            ).filter(
                models.Q(name_lower__contains=query_lower) |
                models.Q(sku_lower__contains=query_lower) |
                models.Q(description_lower__contains=query_lower),
                status='active',
                is_temporary=False
            ).annotate(
                relevance=Case(
                    When(name_lower=query_lower, then=3),
                    When(name_lower__startswith=query_lower, then=2),
                    default=1,
                    output_field=IntegerField()
                )
            ).order_by('-relevance', 'name')
        else:
            kits_query = ProductKit.objects.filter(
                models.Q(name__icontains=query_normalized) |
                models.Q(sku__icontains=query_normalized) |
                models.Q(description__icontains=query_normalized),
                status='active',
                is_temporary=False
            ).annotate(
                relevance=Case(
                    When(name__iexact=query_normalized, then=3),
                    When(name__istartswith=query_normalized, then=2),
                    default=1,
                    output_field=IntegerField()
                )
            ).order_by('-relevance', 'name')

        kits = kits_query[:page_size].values('id', 'name', 'sku', 'price', 'sale_price')

        for kit in kits:
            text = kit['name']
            if kit['sku']:
                text += f" ({kit['sku']})"

            # Получаем actual_price: приоритет sale_price > price
            actual_price = kit['sale_price'] if kit['sale_price'] else kit['price']

            kit_results.append({
                'id': f"kit_{kit['id']}",
                'text': text,
                'sku': kit['sku'],
                'price': str(kit['price']) if kit['price'] else None,
                'actual_price': str(actual_price) if actual_price else '0',
                'type': 'kit'
            })

    # Поиск групп вариантов
    variant_results = []
    if search_type in ['all', 'variant']:
        variants = ProductVariantGroup.objects.filter(
            models.Q(name__icontains=query) |
            models.Q(description__icontains=query)
        ).prefetch_related('items__product')[:page_size]

        for variant in variants:
            count = variant.items.count()
            variant_price = variant.price or 0
            variant_results.append({
                'id': variant.id,
                'text': f"{variant.name} ({count} вариантов)",
                'type': 'variant',
                'count': count,
                'price': str(variant_price),
                'actual_price': str(variant_price)
            })

    # Формируем финальный результат с группировкой или без
    # Для 'all' показываем только товары и комплекты (без вариантов)
    if search_type == 'all':
        if product_results or kit_results:
            # С группировкой для заказов (товары + комплекты)
            grouped_results = []
            if product_results:
                grouped_results.append({
                    'text': 'Товары',
                    'children': product_results
                })
            if kit_results:
                grouped_results.append({
                    'text': 'Комплекты',
                    'children': kit_results
                })
            final_results = grouped_results
        else:
            final_results = []
    elif search_type == 'variant':
        # Только варианты
        final_results = variant_results
    else:
        # Без группировки для специфичного поиска (product или kit)
        final_results = product_results + kit_results + variant_results

    return JsonResponse({
        'results': final_results,
        'pagination': {'more': has_more}
    })


def validate_kit_cost(request):
    """
    AJAX endpoint для валидации себестоимости комплекта в реальном времени.

    Принимает список компонентов и возвращает информацию о валидности себестоимости,
    доступных методах ценообразования и проблемах.

    Request (JSON POST):
    {
        'components': [
            {
                'product_id': int or null,
                'variant_group_id': int or null,
                'quantity': float
            },
            ...
        ]
    }

    Response (JSON):
    {
        'is_valid': bool,
        'total_cost': float or null,
        'problems': [
            {
                'component_name': str,
                'reason': str
            },
            ...
        ],
        'available_methods': {
            'manual': bool,
            'from_sale_prices': bool,
            'from_cost_plus_percent': bool,
            'from_cost_plus_amount': bool
        }
    }
    """
    if request.method != 'POST':
        return JsonResponse({'error': 'Method not allowed'}, status=405)

    try:
        import json
        from decimal import Decimal

        data = json.loads(request.body)
        components = data.get('components', [])

        if not components:
            return JsonResponse({
                'is_valid': False,
                'total_cost': None,
                'problems': [{
                    'component_name': 'Комплект',
                    'reason': 'Комплект не содержит компонентов'
                }],
                'available_methods': {
                    'manual': True,
                    'from_sale_prices': True,
                    'from_cost_plus_percent': False,
                    'from_cost_plus_amount': False
                }
            })

        # Валидируем каждый компонент
        total_cost = Decimal('0.00')
        problems = []

        for idx, component in enumerate(components):
            product_id = component.get('product_id')
            variant_group_id = component.get('variant_group_id')
            quantity = Decimal(str(component.get('quantity', 1)))

            product = None
            product_name = ''

            # Получаем товар
            if product_id:
                try:
                    product = Product.objects.get(id=product_id)
                    product_name = product.name
                except Product.DoesNotExist:
                    problems.append({
                        'component_name': f'Товар #{product_id}',
                        'reason': 'Товар не найден'
                    })
                    continue

            elif variant_group_id:
                try:
                    variant_group = ProductVariantGroup.objects.get(id=variant_group_id)
                    product = variant_group.products.filter(status='active').first()
                    if variant_group:
                        product_name = f"[Варианты] {variant_group.name}"
                except ProductVariantGroup.DoesNotExist:
                    problems.append({
                        'component_name': f'Группа вариантов #{variant_group_id}',
                        'reason': 'Группа не найдена'
                    })
                    continue

            if not product:
                problems.append({
                    'component_name': product_name or f'Компонент {idx + 1}',
                    'reason': 'Товар не выбран или группа пуста'
                })
                continue

            # Проверяем себестоимость
            if product.cost_price is None:
                problems.append({
                    'component_name': product_name,
                    'reason': 'Себестоимость не определена'
                })
                continue

            if product.cost_price <= 0:
                problems.append({
                    'component_name': product_name,
                    'reason': 'Себестоимость равна 0'
                })
                continue

            # Добавляем в сумму
            if quantity > 0:
                total_cost += product.cost_price * quantity

        # Определяем, какие методы доступны
        is_cost_valid = len(problems) == 0
        available_methods = {
            'manual': True,
            'from_sale_prices': True,
            'from_cost_plus_percent': is_cost_valid,
            'from_cost_plus_amount': is_cost_valid
        }

        return JsonResponse({
            'is_valid': is_cost_valid,
            'total_cost': float(total_cost) if is_cost_valid else None,
            'problems': problems,
            'available_methods': available_methods
        })

    except json.JSONDecodeError:
        return JsonResponse({
            'error': 'Invalid JSON'
        }, status=400)
    except Exception as e:
        return JsonResponse({
            'error': str(e)
        }, status=500)


def create_temporary_kit_api(request):
    """
    AJAX endpoint для создания временного комплекта.
    Используется при оформлении заказа для создания букета "на лету".

    Принимает JSON:
    {
        "name": "Букет для Анны",
        "description": "Красные розы и белые лилии",
        "order_id": 123,  // опционально, если заказ уже создан
        "components": [
            {"product_id": 1, "quantity": "5"},
            {"product_id": 2, "quantity": "3"}
        ]
    }

    Возвращает JSON:
    {
        "success": true,
        "kit_id": 456,
        "kit_name": "Букет для Анны",
        "kit_sku": "KIT-000456",
        "kit_price": "1500.00",
        "message": "Временный комплект создан успешно"
    }
    """
    if request.method != 'POST':
        return JsonResponse({
            'success': False,
            'error': 'Метод не поддерживается'
        }, status=405)

    import json
    from ..services.kit_service import create_temporary_kit
    from orders.models import Order

    try:
        data = json.loads(request.body)

        name = data.get('name', '').strip()
        description = data.get('description', '').strip()
        order_id = data.get('order_id')
        components = data.get('components', [])

        # Получаем заказ если указан
        order = None
        if order_id:
            try:
                order = Order.objects.get(pk=order_id)
            except Order.DoesNotExist:
                return JsonResponse({
                    'success': False,
                    'error': f'Заказ #{order_id} не найден'
                }, status=404)

        # Создаем временный комплект через сервис
        kit = create_temporary_kit(
            name=name,
            description=description,
            components=components,
            order=order
        )

        return JsonResponse({
            'success': True,
            'kit_id': kit.id,
            'kit_name': kit.name,
            'kit_sku': kit.sku,
            'kit_price': str(kit.actual_price),
            'message': f'Временный комплект "{kit.name}" создан успешно'
        })

    except ValueError as e:
        logger.warning(f'Validation error при создании временного комплекта: {str(e)}')
        return JsonResponse({
            'success': False,
            'error': str(e)
        }, status=400)
    except json.JSONDecodeError as e:
        logger.error(f'JSON decode error при создании временного комплекта: {str(e)}')
        return JsonResponse({
            'success': False,
            'error': 'Некорректный JSON в запросе'
        }, status=400)
    except ValidationError as e:
        logger.error(f'Django ValidationError при создании временного комплекта: {str(e)}', exc_info=True)
        return JsonResponse({
            'success': False,
            'error': f'Ошибка валидации: {str(e)}'
        }, status=400)
    except Exception as e:
        # Детальное логирование для диагностики 500 ошибок
        try:
            data = json.loads(request.body)
            name = data.get('name', 'N/A')
            order_id = data.get('order_id', 'N/A')
            components_count = len(data.get('components', []))
        except:
            name = 'N/A'
            order_id = 'N/A'
            components_count = 'N/A'

        logger.error(
            f'Непредвиденная ошибка при создании временного комплекта:\n'
            f'  Название: {name}\n'
            f'  Заказ ID: {order_id}\n'
            f'  Количество компонентов: {components_count}\n'
            f'  Пользователь: {request.user.username if request.user.is_authenticated else "Anonymous"}\n'
            f'  Ошибка: {str(e)}',
            exc_info=True
        )

        # Проверяем на типичные ошибки и даём понятные сообщения
        error_msg = str(e).lower()

        if 'недостаточно' in error_msg or 'insufficient' in error_msg or 'stock' in error_msg:
            return JsonResponse({
                'success': False,
                'error': f'Недостаточно товара на складе. {str(e)}'
            }, status=400)
        elif 'integrity' in error_msg or 'constraint' in error_msg:
            return JsonResponse({
                'success': False,
                'error': 'Ошибка целостности данных. Проверьте, что все товары существуют.'
            }, status=400)
        elif 'not found' in error_msg or 'does not exist' in error_msg or 'не найден' in error_msg:
            return JsonResponse({
                'success': False,
                'error': f'Объект не найден: {str(e)}'
            }, status=404)
        else:
            return JsonResponse({
                'success': False,
                'error': f'Не удалось создать комплект: {str(e)}. Проверьте консоль сервера для деталей.'
            }, status=500)


def create_tag_api(request):
    """
    AJAX endpoint для быстрого создания тега из списка тегов.

    Принимает JSON:
    {
        "name": "Новый тег"
    }

    Возвращает JSON:
    {
        "success": true,
        "tag": {
            "id": 1,
            "name": "Новый тег",
            "slug": "novyj-teg",
            "is_active": true,
            "products_count": 0,
            "kits_count": 0
        }
    }

    Или при ошибке:
    {
        "success": false,
        "error": "Описание ошибки"
    }
    """
    if request.method != 'POST':
        return JsonResponse({
            'success': False,
            'error': 'Метод не поддерживается'
        }, status=405)

    try:
        import json
        from django.db import IntegrityError
        from ..models import ProductTag

        data = json.loads(request.body)
        name = data.get('name', '').strip()

        # Валидация
        if not name:
            return JsonResponse({
                'success': False,
                'error': 'Название тега не может быть пустым'
            }, status=400)

        if len(name) > 100:
            return JsonResponse({
                'success': False,
                'error': 'Название тега слишком длинное (максимум 100 символов)'
            }, status=400)

        # Проверка уникальности (регистронезависимо)
        # Примечание: это проверка перед созданием, но race condition все еще возможна
        if ProductTag.objects.filter(name__iexact=name, is_active=True).exists():
            return JsonResponse({
                'success': False,
                'error': f'Тег "{name}" уже существует'
            }, status=400)

        try:
            # Создание тега (slug будет сгенерирован автоматически в модели)
            tag = ProductTag.objects.create(
                name=name,
                is_active=True
            )

            return JsonResponse({
                'success': True,
                'tag': {
                    'id': tag.id,
                    'name': tag.name,
                    'slug': tag.slug,
                    'is_active': tag.is_active,
                    'products_count': 0,
                    'kits_count': 0
                }
            })
        except IntegrityError as e:
            # Защита от race condition: если 2 запроса одновременно попытались создать тег
            error_msg = str(e).lower()
            if 'unique_active_tag_name' in error_msg or ('name' in error_msg and 'duplicate' in error_msg):
                # Тег был создан параллельным запросом, получаем его
                tag = ProductTag.objects.get(name__iexact=name, is_active=True)
                return JsonResponse({
                    'success': True,
                    'tag': {
                        'id': tag.id,
                        'name': tag.name,
                        'slug': tag.slug,
                        'is_active': tag.is_active,
                        'products_count': tag.products.count(),
                        'kits_count': tag.kits.count()
                    }
                })
            elif 'slug' in error_msg:
                # Конфликт slug, это редко должно происходить но обработаем
                return JsonResponse({
                    'success': False,
                    'error': f'Тег с названием "{name}" не может быть создан (конфликт идентификатора). Пожалуйста, попробуйте другое название.'
                }, status=400)
            else:
                return JsonResponse({
                    'success': False,
                    'error': 'Ошибка при создании тега: нарушение уникальности'
                }, status=500)

    except json.JSONDecodeError:
        return JsonResponse({
            'success': False,
            'error': 'Некорректный JSON'
        }, status=400)
    except Exception as e:
        return JsonResponse({
            'success': False,
            'error': f'Ошибка при создании тега: {str(e)}'
        }, status=500)


def toggle_tag_status_api(request, pk):
    """
    AJAX endpoint для переключения статуса активности тега.

    Принимает POST запрос и переключает is_active на противоположное значение.

    Возвращает JSON:
    {
        "success": true,
        "is_active": true/false,
        "message": "Тег активирован" / "Тег деактивирован"
    }

    Или при ошибке:
    {
        "success": false,
        "error": "Описание ошибки"
    }
    """
    if request.method != 'POST':
        return JsonResponse({
            'success': False,
            'error': 'Метод не поддерживается'
        }, status=405)

    try:
        from ..models import ProductTag

        # Получаем тег
        tag = ProductTag.objects.get(pk=pk)

        # Переключаем статус
        tag.is_active = not tag.is_active
        tag.save()

        # Определяем сообщение
        message = "Тег активирован" if tag.is_active else "Тег деактивирован"

        return JsonResponse({
            'success': True,
            'is_active': tag.is_active,
            'message': message
        })

    except ProductTag.DoesNotExist:
        return JsonResponse({
            'success': False,
            'error': 'Тег не найден'
        }, status=404)
    except Exception as e:
        return JsonResponse({
            'success': False,
            'error': f'Ошибка при обновлении тега: {str(e)}'
        }, status=500)


def rename_category_api(request, pk):
    """
    AJAX endpoint для переименования категории (inline editing).

    Принимает JSON:
    {
        "name": "Новое название"
    }

    Возвращает JSON:
    {
        "success": true,
        "name": "Новое название"
    }
    """
    if request.method != 'POST':
        return JsonResponse({
            'success': False,
            'error': 'Метод не поддерживается'
        }, status=405)

    try:
        import json

        data = json.loads(request.body)
        name = data.get('name', '').strip()

        # Валидация
        if not name:
            return JsonResponse({
                'success': False,
                'error': 'Название категории не может быть пустым'
            }, status=400)

        if len(name) > 255:
            return JsonResponse({
                'success': False,
                'error': 'Название слишком длинное (максимум 255 символов)'
            }, status=400)

        # Получаем категорию
        category = ProductCategory.objects.get(pk=pk)

        # Обновляем название
        category.name = name
        category.save(update_fields=['name'])

        return JsonResponse({
            'success': True,
            'name': category.name
        })

    except ProductCategory.DoesNotExist:
        return JsonResponse({
            'success': False,
            'error': 'Категория не найдена'
        }, status=404)
    except json.JSONDecodeError:
        return JsonResponse({
            'success': False,
            'error': 'Некорректный JSON'
        }, status=400)
    except Exception as e:
        return JsonResponse({
            'success': False,
            'error': f'Ошибка при переименовании: {str(e)}'
        }, status=500)


def create_category_api(request):
    """
    AJAX endpoint для создания новой категории (inline creation).

    Принимает JSON:
    {
        "name": "Название категории",
        "parent_id": 123  # опционально, null для корневой категории
    }

    Возвращает JSON:
    {
        "success": true,
        "category": {
            "id": 456,
            "name": "Название категории",
            "slug": "nazvanie-kategorii",
            "parent_id": 123 или null
        }
    }
    """
    if request.method != 'POST':
        return JsonResponse({
            'success': False,
            'error': 'Метод не поддерживается'
        }, status=405)

    try:
        import json
        from django.db import IntegrityError

        data = json.loads(request.body)
        name = data.get('name', '').strip()
        parent_id = data.get('parent_id')

        # Валидация названия
        if not name:
            return JsonResponse({
                'success': False,
                'error': 'Название категории не может быть пустым'
            }, status=400)

        if len(name) > 200:
            return JsonResponse({
                'success': False,
                'error': 'Название слишком длинное (максимум 200 символов)'
            }, status=400)

        # Получаем родительскую категорию, если указана
        parent = None
        if parent_id:
            try:
                parent = ProductCategory.objects.get(pk=parent_id)
                if not parent.is_active:
                    return JsonResponse({
                        'success': False,
                        'error': 'Родительская категория неактивна'
                    }, status=400)
            except ProductCategory.DoesNotExist:
                return JsonResponse({
                    'success': False,
                    'error': 'Родительская категория не найдена'
                }, status=404)

        # Создаем новую категорию
        category = ProductCategory(
            name=name,
            parent=parent,
            is_active=True
        )

        # save() автоматически сгенерирует slug и sku
        category.save()

        return JsonResponse({
            'success': True,
            'category': {
                'id': category.pk,
                'name': category.name,
                'slug': category.slug,
                'parent_id': category.parent_id
            }
        })

    except IntegrityError as e:
        # Определяем тип ошибки уникальности
        error_str = str(e).lower()
        if 'unique_active_category_name' in error_str or 'unique constraint' in error_str:
            error_message = 'Категория с таким названием уже существует'
        elif 'sku' in error_str:
            error_message = 'Ошибка при генерации артикула. Попробуйте ещё раз'
        else:
            error_message = 'Ошибка: категория с такими данными уже существует'

        return JsonResponse({
            'success': False,
            'error': error_message
        }, status=400)
    except json.JSONDecodeError:
        return JsonResponse({
            'success': False,
            'error': 'Некорректный JSON'
        }, status=400)
    except ValidationError as e:
        # ValidationError может содержать словарь с ошибками
        if hasattr(e, 'message_dict'):
            # Извлекаем первое сообщение из словаря
            error_messages = []
            for field, messages in e.message_dict.items():
                if isinstance(messages, list):
                    error_messages.extend(messages)
                else:
                    error_messages.append(str(messages))
            error_text = ' '.join(error_messages)
        elif hasattr(e, 'messages'):
            error_text = ' '.join(e.messages)
        else:
            error_text = str(e)

        # Заменяем технические сообщения на понятные
        if 'unique_active_category_name' in error_text.lower():
            error_text = 'Категория с таким названием уже существует'
        elif 'циклическая ссылка' in error_text.lower():
            error_text = 'Невозможно создать категорию: обнаружена циклическая ссылка'
        elif 'слишком глубокая вложенность' in error_text.lower():
            error_text = 'Превышена максимальная глубина вложенности категорий'

        return JsonResponse({
            'success': False,
            'error': error_text
        }, status=400)
    except Exception as e:
        logger.error(f'Ошибка при создании категории: {str(e)}')
        return JsonResponse({
            'success': False,
            'error': f'Ошибка при создании категории: {str(e)}'
        }, status=500)


@login_required
def update_product_price_api(request, pk):
    """
    AJAX endpoint для изменения цены товара (inline editing в каталоге).

    Принимает JSON:
    {
        "field": "price" | "sale_price",
        "value": "150.50" | null
    }

    Возвращает JSON:
    {
        "success": true,
        "price": "199.00",
        "sale_price": "150.00" | null,
        "actual_price": "150.00"
    }
    """
    if request.method != 'POST':
        return JsonResponse({
            'success': False,
            'error': 'Метод не поддерживается'
        }, status=405)

    # Проверка прав доступа через кастомную систему ролей
    from user_roles.services import RoleService
    
    # Добавляем отладочное логирование
    try:
        logger.info(f"Update price API - User: {request.user.email}, is_superuser: {request.user.is_superuser}")
        user_role = RoleService.get_user_role(request.user)
        logger.info(f"Update price API - User role: {user_role.code if user_role else 'None'}")
    except Exception as e:
        logger.error(f"Update price API - Error getting user role: {str(e)}")
    
    # Owner и Manager имеют право изменять цены
    if not request.user.is_superuser and not RoleService.user_has_role(request.user, 'owner', 'manager'):
        logger.warning(f"Update price API - Access denied for user {request.user.email}")
        return JsonResponse({
            'success': False,
            'error': 'У вас нет прав для изменения цен товаров'
        }, status=403)

    try:
        import json
        from decimal import Decimal, InvalidOperation

        data = json.loads(request.body)
        field = data.get('field')
        value = data.get('value')

        # Валидация поля
        if field not in ['price', 'sale_price']:
            return JsonResponse({
                'success': False,
                'error': 'Недопустимое поле. Разрешены: price, sale_price'
            }, status=400)

        # Получаем товар
        product = Product.objects.get(pk=pk)

        # Обработка значения
        if value is None:
            # Очистка sale_price
            if field == 'sale_price':
                product.sale_price = None
            else:
                return JsonResponse({
                    'success': False,
                    'error': 'Основная цена не может быть пустой'
                }, status=400)
        else:
            # Валидация значения
            try:
                decimal_value = Decimal(str(value))
            except (InvalidOperation, ValueError):
                return JsonResponse({
                    'success': False,
                    'error': 'Некорректное числовое значение'
                }, status=400)

            # Проверка диапазона
            if decimal_value <= 0:
                return JsonResponse({
                    'success': False,
                    'error': 'Цена должна быть положительной'
                }, status=400)

            if decimal_value > Decimal('999999.99'):
                return JsonResponse({
                    'success': False,
                    'error': 'Цена слишком большая (максимум 999999.99)'
                }, status=400)

            # Проверка десятичных знаков
            if decimal_value.as_tuple().exponent < -2:
                return JsonResponse({
                    'success': False,
                    'error': 'Максимум 2 знака после запятой'
                }, status=400)

            # Устанавливаем значение
            if field == 'price':
                product.price = decimal_value
                # Проверка: sale_price должна быть меньше price
                if product.sale_price and product.sale_price >= decimal_value:
                    return JsonResponse({
                        'success': False,
                        'error': 'Скидочная цена должна быть меньше обычной цены'
                    }, status=400)
            else:  # sale_price
                # Проверка: sale_price должна быть меньше price
                if decimal_value >= product.price:
                    return JsonResponse({
                        'success': False,
                        'error': 'Скидочная цена должна быть меньше обычной цены'
                    }, status=400)
                product.sale_price = decimal_value

        # Сохраняем
        product.save(update_fields=[field])

        # Возвращаем обновлённые данные
        return JsonResponse({
            'success': True,
            'price': str(product.price),
            'sale_price': str(product.sale_price) if product.sale_price else None,
            'actual_price': str(product.actual_price)
        })

    except Product.DoesNotExist:
        return JsonResponse({
            'success': False,
            'error': 'Товар не найден'
        }, status=404)
    except json.JSONDecodeError:
        return JsonResponse({
            'success': False,
            'error': 'Некорректный JSON'
        }, status=400)
    except Exception as e:
        logger.error(f'Ошибка при обновлении цены товара: {str(e)}')
        return JsonResponse({
            'success': False,
            'error': f'Ошибка при обновлении цены: {str(e)}'
        }, status=500)


def get_payment_methods(request):
    """
    API endpoint для получения списка активных способов оплаты.
    Используется для динамической загрузки payment methods в JavaScript.

    Возвращает JSON:
    [
        {
            "id": 1,
            "name": "Наличные курьеру",
            "code": "cash_to_courier",
            "description": "Оплата наличными при получении заказа"
        },
        ...
    ]
    """
    try:
        from orders.models import PaymentMethod

        # Получаем все активные способы оплаты, упорядоченные по полю order и названию
        payment_methods = PaymentMethod.objects.filter(
            is_active=True
        ).order_by('order', 'name').values('id', 'name', 'code', 'description')

        # Преобразуем QuerySet в список
        methods_list = list(payment_methods)

        return JsonResponse(methods_list, safe=False)

    except Exception as e:
        logger.error(f'Ошибка при загрузке способов оплаты: {str(e)}')
        return JsonResponse({
            'error': f'Ошибка при загрузке способов оплаты: {str(e)}'
        }, status=500)

@login_required
def get_product_sales_units_api(request, product_id):
    """
    API для получения единиц продажи товара с остатками.

    GET /api/products/{product_id}/sales-units/?warehouse={id}

    Параметры GET:
    - warehouse: ID склада для получения остатков (опционально)

    Возвращает JSON:
    {
        "success": true,
        "product_id": 123,
        "product_name": "Роза красная Freedom 50см",
        "sales_units": [
            {
                "id": 1,
                "name": "Ветка большая",
                "unit_code": "шт",
                "unit_short_name": "шт",
                "price": "150.00",
                "sale_price": "135.00",
                "actual_price": "135.00",
                "conversion_factor": "15.000000",
                "min_quantity": "1.000",
                "quantity_step": "1.000",
                "is_default": true,
                "available_quantity": "45.000000"
            }
        ]
    }
    """
    try:
        from decimal import Decimal
        warehouse_id = request.GET.get('warehouse', '').strip()

        # Получаем товар с prefetch единиц продажи
        product = Product.objects.prefetch_related('sales_units').get(
            id=product_id, status='active'
        )

        # Получаем остатки со склада
        from inventory.models import Stock
        available_qty = Decimal('0')
        if warehouse_id:
            try:
                stock = Stock.objects.filter(
                    product_id=product_id,
                    warehouse_id=int(warehouse_id)
                ).first()
                if stock:
                    available_qty = stock.quantity_available - stock.quantity_reserved
            except (ValueError, Stock.DoesNotExist):
                pass

        # Формируем список единиц с пересчётом остатков
        sales_units_data = []
        for su in product.sales_units.filter(is_active=True).order_by('position', 'id'):
            qty_in_unit = su.convert_from_base(available_qty) if available_qty > 0 else Decimal('0')

            sales_units_data.append({
                'id': su.id,
                'name': su.name,
                'price': str(su.price),
                'sale_price': str(su.sale_price) if su.sale_price else None,
                'actual_price': str(su.actual_price),
                'conversion_factor': str(su.conversion_factor),
                'min_quantity': str(su.min_quantity),
                'quantity_step': str(su.quantity_step),
                'is_default': su.is_default,
                'available_quantity': str(qty_in_unit)
            })

        return JsonResponse({
            'success': True,
            'product_id': product.id,
            'product_name': product.name,
            'sales_units': sales_units_data
        })

    except Product.DoesNotExist:
        return JsonResponse({
            'success': False,
            'error': 'Товар не найден'
        }, status=404)
    except Exception as e:
        logger.error(f'Ошибка загрузки единиц продажи: {str(e)}')
        return JsonResponse({
            'success': False,
            'error': str(e)
        }, status=500)


@login_required
def get_filtered_items_ids(request):
    """
    API endpoint для получения ID всех отфильтрованных товаров и комплектов.
    Используется для функции "Выбрать все отфильтрованные".
    
    Параметры GET (те же, что и в CombinedProductListView):
    - search: строка поиска
    - type: 'all', 'products', 'kits'
    - category: ID категории
    - status: статус товара/комплекта
    - in_stock: '1' или '0'
    - tags: список ID тегов
    
    Возвращает JSON:
    {
        "success": true,
        "items": [
            {"type": "product", "id": 1},
            {"type": "kit", "id": 5},
            ...
        ],
        "count": 150
    }
    """
    from django.db.models import Q
    from ..models import Product, ProductKit
    
    try:
        # Получаем фильтры из GET-параметров
        type_filter = request.GET.get('type', 'all')
        search_query = request.GET.get('search')
        category_id = request.GET.get('category')
        status_filter = request.GET.get('status')
        in_stock_filter = request.GET.get('in_stock')
        tags = request.GET.getlist('tags')
        
        # Начинаем с базовых queryset
        products = Product.objects.all()
        kits = ProductKit.objects.filter(is_temporary=False)
        
        # Применяем фильтры (та же логика, что в CombinedProductListView)
        if search_query:
            products = products.filter(
                Q(name__icontains=search_query) |
                Q(sku__icontains=search_query) |
                Q(description__icontains=search_query) |
                Q(categories__name__icontains=search_query) |
                Q(search_keywords__icontains=search_query)
            ).distinct()
            
            kits = kits.filter(
                Q(name__icontains=search_query) |
                Q(sku__icontains=search_query) |
                Q(description__icontains=search_query) |
                Q(categories__name__icontains=search_query)
            ).distinct()
        
        if category_id:
            products = products.filter(categories__id=category_id)
            kits = kits.filter(categories__id=category_id)
        
        if status_filter:
            products = products.filter(status=status_filter)
            kits = kits.filter(status=status_filter)
        
        if in_stock_filter == '1':
            products = products.filter(in_stock=True)
        elif in_stock_filter == '0':
            products = products.filter(in_stock=False)
        
        if tags:
            products = products.filter(tags__id__in=tags).distinct()
            kits = kits.filter(tags__id__in=tags).distinct()
        
        # Собираем ID в зависимости от фильтра типа
        items = []
        
        if type_filter in ['all', 'products']:
            product_ids = products.values_list('id', flat=True)
            items.extend([{'type': 'product', 'id': pid} for pid in product_ids])
        
        if type_filter in ['all', 'kits']:
            kit_ids = kits.values_list('id', flat=True)
            items.extend([{'type': 'kit', 'id': kid} for kid in kit_ids])
        
        return JsonResponse({
            'success': True,
            'items': items,
            'count': len(items)
        })
        
    except Exception as e:
        logger.error(f'Ошибка получения отфильтрованных ID: {str(e)}')
        return JsonResponse({
            'success': False,
            'error': str(e)
        }, status=500)


@login_required
def bulk_update_categories(request):
    """
    API endpoint для массового обновления категорий у выбранных товаров и комплектов.
    
    POST /products/api/bulk-update-categories/
    
    Request JSON:
    {
        "items": [
            {"type": "product", "id": 123},
            {"type": "kit", "id": 456}
        ],
        "category_ids": [5, 12, 18],
        "action_mode": "add",  // "add", "replace" или "clear"
        "external_category_id": 7  // опционально, для установки внешней категории
    }
    
    Response JSON:
    {
        "success": true,
        "updated_count": 15,
        "skipped_count": 0,
        "message": "Категории успешно обновлены для 15 товаров"
    }
    """
    if request.method != 'POST':
        return JsonResponse({
            'success': False,
            'message': 'Метод не поддерживается'
        }, status=405)
    
    try:
        import json
        from django.db import transaction
        
        # Парсинг JSON запроса
        try:
            data = json.loads(request.body)
        except json.JSONDecodeError:
            return JsonResponse({
                'success': False,
                'message': 'Неверный формат JSON'
            }, status=400)
        
        # Валидация обязательных полей
        items = data.get('items', [])
        category_ids = data.get('category_ids', [])
        action_mode = data.get('action_mode', 'add')
        external_category_id = data.get('external_category_id')  # Может быть null для очистки
        should_clear_external = data.get('clear_external_category', False)
        
        if not items:
            return JsonResponse({
                'success': False,
                'message': 'Не выбраны товары для обновления'
            }, status=400)
        
        # Для режима 'clear' категории не обязательны, но нужна либо M2M категория, либо внешняя
        if action_mode != 'clear' and not category_ids and external_category_id is None and not should_clear_external:
            return JsonResponse({
                'success': False,
                'message': 'Не выбраны категории'
            }, status=400)
        
        if action_mode not in ['add', 'replace', 'clear']:
            return JsonResponse({
                'success': False,
                'message': 'Неверный режим действия (должен быть add, replace или clear)'
            }, status=400)
        
        # Проверка существования M2M категорий (только если они указаны)
        categories = []
        if category_ids:
            categories = ProductCategory.objects.filter(id__in=category_ids, is_active=True)
            if categories.count() != len(category_ids):
                return JsonResponse({
                    'success': False,
                    'message': 'Некоторые категории не найдены или неактивны'
                }, status=400)
        
        # Проверка существования внешней категории (если указана)
        external_category = None
        if external_category_id is not None:
            try:
                external_category = ProductCategory.objects.get(id=external_category_id, is_active=True)
            except ProductCategory.DoesNotExist:
                return JsonResponse({
                    'success': False,
                    'message': 'Главная категория не найдена или неактивна'
                }, status=400)
        
        # Проверка: нельзя одновременно устанавливать и очищать внешнюю категорию
        if external_category and should_clear_external:
            return JsonResponse({
                'success': False,
                'message': 'Нельзя одновременно установить и очистить главную категорию'
            }, status=400)
        
        # Обработка товаров в транзакции
        updated_count = 0
        skipped_count = 0
        skipped_reasons = []
        
        with transaction.atomic():
            for item in items:
                item_type = item.get('type')
                item_id = item.get('id')
                
                if not item_type or not item_id:
                    skipped_count += 1
                    continue
                
                try:
                    # Получаем объект товара или комплекта
                    if item_type == 'product':
                        # Проверка прав
                        if not request.user.has_perm('products.change_product'):
                            skipped_count += 1
                            skipped_reasons.append(f'Товар ID {item_id}: нет прав')
                            continue
                        
                        obj = Product.objects.get(id=item_id)
                    elif item_type == 'kit':
                        # Проверка прав
                        if not request.user.has_perm('products.change_productkit'):
                            skipped_count += 1
                            skipped_reasons.append(f'Комплект ID {item_id}: нет прав')
                            continue
                        
                        obj = ProductKit.objects.get(id=item_id)
                    else:
                        skipped_count += 1
                        continue
                    
                    # Применяем изменения M2M категорий
                    if action_mode == 'add':
                        # Добавляем категории к существующим
                        obj.categories.add(*categories)
                    elif action_mode == 'replace':
                        # Заменяем все категории
                        obj.categories.set(categories)
                    elif action_mode == 'clear':
                        # Очищаем все категории
                        obj.categories.clear()
                    
                    # Применяем изменения внешней категории
                    if external_category:
                        obj.external_category = external_category
                        obj.save(update_fields=['external_category'])
                    elif should_clear_external:
                        obj.external_category = None
                        obj.save(update_fields=['external_category'])
                    
                    updated_count += 1
                    
                except (Product.DoesNotExist, ProductKit.DoesNotExist):
                    skipped_count += 1
                    skipped_reasons.append(f'{item_type.capitalize()} ID {item_id} не найден')
                    continue
                except Exception as e:
                    logger.error(f'Ошибка обновления {item_type} ID {item_id}: {str(e)}')
                    skipped_count += 1
                    skipped_reasons.append(f'{item_type.capitalize()} ID {item_id}: {str(e)}')
                    continue
        
        # Формируем сообщение результата
        if updated_count > 0:
            message_parts = []
            
            # Сообщение про M2M категории
            if action_mode == 'clear':
                if categories or action_mode == 'clear':
                    message_parts.append(f'Категории удалены')
            else:
                if categories:
                    category_names = ', '.join([c.name for c in categories[:3]])
                    if len(categories) > 3:
                        category_names += f' и ещё {len(categories) - 3}'
                    
                    if action_mode == 'add':
                        action_text = 'добавлены'
                    else:
                        action_text = 'установлены'
                    
                    message_parts.append(f'Категории "{category_names}" {action_text}')
            
            # Сообщение про внешнюю категорию
            if external_category:
                message_parts.append(f'Внешняя категория "{external_category.name}" установлена')
            elif should_clear_external:
                message_parts.append('Внешняя категория очищена')
            
            # Собираем финальное сообщение
            if message_parts:
                message = f'{", ".join(message_parts)} для {updated_count} товаров'
            else:
                message = f'Обновлено {updated_count} товаров'
            
            if skipped_count > 0:
                message += f'. Пропущено: {skipped_count}'
            
            response_data = {
                'success': True,
                'updated_count': updated_count,
                'skipped_count': skipped_count,
                'message': message
            }
            
            if skipped_reasons:
                response_data['skipped_reasons'] = skipped_reasons[:10]  # Ограничение первыми 10
            
            return JsonResponse(response_data)
        else:
            return JsonResponse({
                'success': False,
                'updated_count': 0,
                'skipped_count': skipped_count,
                'message': 'Не удалось обновить ни один товар',
                'skipped_reasons': skipped_reasons[:10]
            }, status=400)
    
    except Exception as e:
        logger.error(f'Ошибка массового обновления категорий: {str(e)}')
        return JsonResponse({
            'success': False,
            'message': f'Произошла ошибка: {str(e)}'
        }, status=500)


# ========== Генератор названий букетов ==========

from django.views import View
from ..models import BouquetName
from ..services import BouquetNameGenerator


class RandomBouquetNamesView(View):
    """Возвращает случайные названия из базы"""

    def get(self, request):
        count = int(request.GET.get('count', 3))
        # Ограничиваем максимум до 100
        count = min(count, 100)

        # Получаем случайные названия с ID (любые, не только одобренные)
        queryset = BouquetName.objects.order_by('?')[:count]
        names_data = [{'id': obj.id, 'name': obj.name} for obj in queryset]

        return JsonResponse({'names': names_data})


class GenerateBouquetNamesView(View):
    """Генерирует новые названия через LLM и сохраняет в базу"""

    def post(self, request):
        count = int(request.POST.get('count', 10))
        # Ограничиваем максимум до 500
        count = min(count, 500)

        generator = BouquetNameGenerator()

        success, msg, data = generator.generate_and_store(
            count=count,
            language='russian'
        )

        if success:
            return JsonResponse({
                'success': True,
                'message': msg,
                'count': len(data.get('names', []))
            })
        else:
            return JsonResponse({'success': False, 'error': msg}, status=400)


class DeleteBouquetNameView(View):
    """Удаляет конкретное название из базы"""

    def delete(self, request, pk):
        try:
            name_obj = BouquetName.objects.get(pk=pk)
            name_obj.delete()
            return JsonResponse({'success': True})
        except BouquetName.DoesNotExist:
            return JsonResponse({'success': False, 'error': 'Название не найдено'}, status=404)
        except Exception as e:
            return JsonResponse({'success': False, 'error': str(e)}, status=500)


class GetBouquetNamesCountView(View):
    """Возвращает количество названий в базе"""

    def get(self, request):
        count = BouquetName.objects.count()
        return JsonResponse({'count': count})
