"""
CRUD представления для товаров (Product).
"""
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import ListView, CreateView, DetailView, UpdateView, DeleteView
from django.urls import reverse_lazy
from django.db.models import Q, Sum, Value, DecimalField
from django.db.models.functions import Coalesce
from itertools import chain

from ..models import Product, ProductCategory, ProductTag, ProductKit
from ..forms import ProductForm, ProductSalesUnitFormSet
from .utils import handle_photos
from ..models import ProductPhoto
from user_roles.mixins import ManagerOwnerRequiredMixin


class ProductListView(LoginRequiredMixin, ManagerOwnerRequiredMixin, ListView):
    model = Product
    template_name = 'products/product_list.html'
    context_object_name = 'products'
    paginate_by = 10

    def get_queryset(self):
        queryset = super().get_queryset()
        # Добавляем prefetch_related для оптимизации запросов к категориям
        queryset = queryset.prefetch_related('categories', 'photos', 'tags')

        # Улучшенный поиск по нескольким полям
        search_query = self.request.GET.get('search')
        if search_query:
            # Ищем по названию, артикулу, описанию, категориям и ключевым словам
            queryset = queryset.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()

        # Фильтр по категории
        category_id = self.request.GET.get('category')
        if category_id:
            queryset = queryset.filter(categories__id=category_id)

        # Фильтр по статусу (новая система)
        status_filter = self.request.GET.get('status')
        if status_filter:
            queryset = queryset.filter(status=status_filter)
        else:
            # Фильтр по is_active для обратной совместимости (старая система)
            is_active_filter = self.request.GET.get('is_active')
            if is_active_filter == '1':
                queryset = queryset.filter(status='active')
            elif is_active_filter == '0':
                queryset = queryset.filter(status__in=['archived', 'discontinued'])

        # Фильтр по тегам
        tags = self.request.GET.getlist('tags')
        if tags:
            queryset = queryset.filter(tags__id__in=tags).distinct()

        return queryset.order_by('-created_at')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        # Данные для фильтров
        context['filters'] = {
            'categories': ProductCategory.objects.filter(is_active=True),
            'tags': ProductTag.objects.filter(is_active=True),
            'current': {
                'search': self.request.GET.get('search', ''),
                'category': self.request.GET.get('category', ''),
                'status': self.request.GET.get('status', ''),
                'tags': self.request.GET.getlist('tags'),
            }
        }

        # Кнопки действий
        action_buttons = []

        if self.request.user.has_perm('products.add_product'):
            action_buttons.append({
                'url': reverse_lazy('products:product-create'),
                'text': 'Создать товар',
                'class': 'btn-primary',
                'icon': 'plus-circle'
            })

        if self.request.user.has_perm('products.add_productkit'):
            action_buttons.append({
                'url': reverse_lazy('products:productkit-create'),
                'text': 'Создать комплект',
                'class': 'btn-outline-primary',
                'icon': 'box-seam'
            })

        context['action_buttons'] = action_buttons

        return context


class ProductCreateView(LoginRequiredMixin, ManagerOwnerRequiredMixin, CreateView):
    model = Product
    form_class = ProductForm
    template_name = 'products/product_form.html'

    def get_success_url(self):
        return reverse_lazy('products:products-list')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        if self.request.POST:
            context['sales_unit_formset'] = ProductSalesUnitFormSet(
                self.request.POST,
                prefix='sales_units'
            )
        else:
            context['sales_unit_formset'] = ProductSalesUnitFormSet(prefix='sales_units')
        return context

    def form_valid(self, form):
        from django.db import IntegrityError

        context = self.get_context_data()
        sales_unit_formset = context['sales_unit_formset']

        try:
            # Сначала сохраняем товар
            self.object = form.save()

            # Затем сохраняем единицы продажи
            if sales_unit_formset.is_valid():
                sales_unit_formset.instance = self.object
                sales_unit_formset.save()
            else:
                # Если formset невалиден, показываем ошибки
                for error in sales_unit_formset.errors:
                    if error:
                        messages.warning(self.request, f'Ошибка в единицах продажи: {error}')

            # Обработка загрузки фотографий
            photo_errors = handle_photos(self.request, self.object, ProductPhoto, 'product')
            if photo_errors:
                for error in photo_errors:
                    # Если это предупреждение о лимите фото - warning, иначе - error
                    if 'Загружено' in error and 'обработано только' in error:
                        messages.warning(self.request, error)
                    else:
                        messages.error(self.request, error)

            messages.success(self.request, f'Товар "{form.instance.name}" успешно создан!')
            return super().form_valid(form)

        except IntegrityError as e:
            # Обработка ошибки дублирования slug'а или других unique constraints
            error_msg = str(e).lower()
            if 'slug' in error_msg or 'duplicate key' in error_msg:
                messages.error(
                    self.request,
                    f'Ошибка: товар с названием "{form.instance.name}" уже существует. '
                    'Пожалуйста, используйте другое название.'
                )
            else:
                messages.error(
                    self.request,
                    'Ошибка при сохранении товара. Пожалуйста, проверьте введённые данные.'
                )

            # Перенаправляем обратно на форму с сохранённой информацией
            return self.form_invalid(form)


class ProductDetailView(LoginRequiredMixin, ManagerOwnerRequiredMixin, DetailView):
    model = Product
    template_name = 'products/product_detail.html'
    context_object_name = 'product'

    def get_queryset(self):
        # Предзагрузка фотографий, категорий, тегов и аннотация остатков
        total_available = Coalesce(Sum('stocks__quantity_available'), Value(0), output_field=DecimalField())
        total_reserved = Coalesce(Sum('stocks__quantity_reserved'), Value(0), output_field=DecimalField())
        return super().get_queryset().prefetch_related(
            'photos',
            'categories',
            'tags',
            'sales_units'
        ).annotate(
            total_available=total_available,
            total_reserved=total_reserved,
            total_free=total_available - total_reserved,
        )

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # Добавляем фотографии товара в контекст (используем уже загруженные через prefetch_related)
        product_photos = list(self.object.photos.all())
        product_photos.sort(key=lambda x: (x.order, x.created_at))
        context['product_photos'] = product_photos
        context['photos_count'] = len(product_photos)

        # Кешируем cost_price_details, чтобы не делать множественные запросы к БД
        from ..services.cost_calculator import ProductCostCalculator
        context['cost_price_details'] = ProductCostCalculator.get_cost_details(self.object)

        # Единицы продажи (активные, отсортированные)
        context['sales_units'] = self.object.sales_units.filter(is_active=True).order_by('position', 'name')

        # Комплекты, в которых этот товар используется как единица продажи
        context['kit_items_using_sales_units'] = self.object.kit_items_using_as_sales_unit.select_related('kit', 'sales_unit').prefetch_related('kit__photos')

        # Комплекты, в которых этот товар используется напрямую
        context['kit_items_using_products'] = self.object.kit_items_direct.select_related('kit').prefetch_related('kit__photos')

        # Комплекты, в которых этот товар используется как часть группы вариантов
        context['variant_group_kit_items'] = self.object.variant_group_items.select_related('variant_group').prefetch_related('variant_group__kit_items__kit__photos')

        return context


class ProductUpdateView(LoginRequiredMixin, ManagerOwnerRequiredMixin, UpdateView):
    model = Product
    form_class = ProductForm
    template_name = 'products/product_form.html'

    def get_success_url(self):
        return reverse_lazy('products:products-list')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # Добавляем фотографии товара в контекст
        context['product_photos'] = self.object.photos.all().order_by('order', 'created_at')
        context['photos_count'] = self.object.photos.count()

        # Добавляем formset единиц продажи
        if self.request.POST:
            context['sales_unit_formset'] = ProductSalesUnitFormSet(
                self.request.POST,
                instance=self.object,
                prefix='sales_units'
            )
        else:
            context['sales_unit_formset'] = ProductSalesUnitFormSet(
                instance=self.object,
                prefix='sales_units'
            )
        return context

    def form_valid(self, form):
        from django.db import IntegrityError

        context = self.get_context_data()
        sales_unit_formset = context['sales_unit_formset']

        try:
            # Сначала сохраняем товар
            self.object = form.save()

            # Затем сохраняем единицы продажи
            if sales_unit_formset.is_valid():
                sales_unit_formset.instance = self.object
                sales_unit_formset.save()
            else:
                # Если formset невалиден, показываем ошибки
                for error in sales_unit_formset.errors:
                    if error:
                        messages.warning(self.request, f'Ошибка в единицах продажи: {error}')

            # Обработка загрузки фотографий
            photo_errors = handle_photos(self.request, self.object, ProductPhoto, 'product')
            if photo_errors:
                for error in photo_errors:
                    # Если это предупреждение о лимите фото - warning, иначе - error
                    if 'Загружено' in error and 'обработано только' in error:
                        messages.warning(self.request, error)
                    else:
                        messages.error(self.request, error)

            messages.success(self.request, f'Товар "{form.instance.name}" успешно обновлен!')
            return super().form_valid(form)

        except IntegrityError as e:
            # Обработка ошибки дублирования slug'а или других unique constraints
            error_msg = str(e).lower()
            if 'slug' in error_msg or 'duplicate key' in error_msg:
                messages.error(
                    self.request,
                    f'Ошибка: товар с названием "{form.instance.name}" уже существует. '
                    'Пожалуйста, используйте другое название.'
                )
            else:
                messages.error(
                    self.request,
                    'Ошибка при сохранении товара. Пожалуйста, проверьте введённые данные.'
                )

            # Перенаправляем обратно на форму с сохранённой информацией
            return self.form_invalid(form)


class ProductDeleteView(LoginRequiredMixin, ManagerOwnerRequiredMixin, DeleteView):
    model = Product
    template_name = 'products/product_confirm_delete.html'
    context_object_name = 'product'

    def get_success_url(self):
        messages.success(self.request, f'Товар "{self.object.name}" успешно удален!')
        return reverse_lazy('products:products-list')


class CombinedProductListView(LoginRequiredMixin, ManagerOwnerRequiredMixin, ListView):
    """
    Объединенное представление для товаров и комплектов.
    Показывает оба типа продуктов в одном списке с возможностью фильтрации по типу.
    """
    template_name = 'products/products_list.html'
    context_object_name = 'items'
    paginate_by = 20

    def get_paginate_by(self, queryset):
        """
        Динамическое определение количества элементов на странице.
        Читает параметр per_page из GET-запроса.
        """
        per_page = self.request.GET.get('per_page', '20')
        try:
            per_page_int = int(per_page)
            # Разрешаем только значения 20, 50, 100
            if per_page_int in [20, 50, 100]:
                return per_page_int
        except (ValueError, TypeError):
            pass
        # По умолчанию возвращаем 20
        return 20

    def get_queryset(self):
        # Получаем фильтр по типу
        type_filter = self.request.GET.get('type', 'all')

        # Получаем товары и комплекты (только постоянные комплекты)
        # Аннотируем товары данными об остатках из агрегированной таблицы Stock
        total_available = Coalesce(Sum('stocks__quantity_available'), Value(0), output_field=DecimalField())
        total_reserved = Coalesce(Sum('stocks__quantity_reserved'), Value(0), output_field=DecimalField())
        products = Product.objects.prefetch_related('categories', 'photos', 'tags').annotate(
            total_available=total_available,
            total_reserved=total_reserved,
            total_free=total_available - total_reserved,
        )
        kits = ProductKit.objects.filter(is_temporary=False).prefetch_related('categories', 'photos', 'tags')

        # Применяем фильтры
        search_query = self.request.GET.get('search')
        category_id = self.request.GET.get('category')
        status_filter = self.request.GET.get('status')
        is_active_filter = self.request.GET.get('is_active')
        in_stock_filter = self.request.GET.get('in_stock')
        tags = self.request.GET.getlist('tags')

        # Фильтрация по поиску
        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)
        else:
            # Фильтрация по is_active для обратной совместимости (старая система)
            if is_active_filter == '1':
                products = products.filter(status='active')
                kits = kits.filter(status='active')
            elif is_active_filter == '0':
                products = products.filter(status__in=['archived', 'discontinued'])
                kits = kits.filter(status__in=['archived', 'discontinued'])

        # Фильтрация по наличию (только для товаров)
        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()

        # Фильтр по цене
        price_from = self.request.GET.get('price_from')
        price_to = self.request.GET.get('price_to')
        if price_from:
            products = products.filter(
                Q(sale_price__gte=price_from) | Q(price__gte=price_from)
            ).distinct()
            kits = kits.filter(
                Q(sale_price__gte=price_from) | Q(price__gte=price_from)
            ).distinct()
        if price_to:
            products = products.filter(
                Q(sale_price__lte=price_to) | Q(price__lte=price_to)
            ).distinct()
            kits = kits.filter(
                Q(sale_price__lte=price_to) | Q(price__lte=price_to)
            ).distinct()

        # Маркетинговые фильтры (OR логика — объединяются через Q)
        marketing_filters = Q()
        if self.request.GET.get('is_new') == '1':
            marketing_filters |= Q(is_new=True)
        if self.request.GET.get('is_popular') == '1':
            marketing_filters |= Q(is_popular=True)
        if self.request.GET.get('is_special') == '1':
            marketing_filters |= Q(is_special=True)
        if marketing_filters:
            products = products.filter(marketing_filters)
            kits = kits.filter(marketing_filters)

        # Фильтр по скидке
        has_discount = self.request.GET.get('has_discount')
        if has_discount == '1':
            products = products.filter(sale_price__gt=0)
            kits = kits.filter(sale_price__gt=0)

        # Применяем фильтр по типу
        products_list = []
        kits_list = []

        if type_filter in ['all', 'products']:
            products_list = list(products.order_by('-created_at'))
            for p in products_list:
                p.item_type = 'product'

        if type_filter in ['all', 'kits']:
            kits_list = list(kits.order_by('-created_at'))
            for k in kits_list:
                k.item_type = 'kit'
                # Рассчитываем доступное количество комплектов (для отображения остатков)
                k.total_free = k.calculate_available_quantity()

        # Объединяем и сортируем по дате создания
        combined = sorted(
            chain(products_list, kits_list),
            key=lambda x: x.created_at,
            reverse=True
        )

        return combined

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        # Получаем список статусов из модели
        from ..models.base import BaseProductEntity
        item_statuses = BaseProductEntity.STATUS_CHOICES

        # Получаем состояние интеграции Recommerce
        from integrations.models import RecommerceIntegration
        recommerce_integration = RecommerceIntegration.objects.first()
        context['recommerce_integration_enabled'] = recommerce_integration.is_active if recommerce_integration else False

        # Данные для фильтров
        context['filters'] = {
            'categories': ProductCategory.objects.filter(is_active=True),
            'tags': ProductTag.objects.filter(is_active=True),
            'current': {
                'search': self.request.GET.get('search', ''),
                'category': self.request.GET.get('category', ''),
                'status': self.request.GET.get('status', ''),
                'type': self.request.GET.get('type', 'all'),
                'in_stock': self.request.GET.get('in_stock', ''),
                'tags': [int(tag) for tag in self.request.GET.getlist('tags') if tag.isdigit()],
                'per_page': self.request.GET.get('per_page', '20'),
                'price_from': self.request.GET.get('price_from', ''),
                'price_to': self.request.GET.get('price_to', ''),
                'is_new': self.request.GET.get('is_new', ''),
                'is_popular': self.request.GET.get('is_popular', ''),
                'is_special': self.request.GET.get('is_special', ''),
                'has_discount': self.request.GET.get('has_discount', ''),
            }
        }

        context['item_statuses'] = item_statuses

        # Кнопки действий
        # Проверяем права через has_perm, который использует наш RoleBasedPermissionBackend
        action_buttons = []

        if self.request.user.has_perm('products.add_product'):
            action_buttons.append({
                'url': reverse_lazy('products:product-create'),
                'text': 'Создать товар',
                'class': 'btn-primary',
                'icon': 'plus-circle'
            })

        if self.request.user.has_perm('products.add_productkit'):
            action_buttons.append({
                'url': reverse_lazy('products:productkit-create'),
                'text': 'Создать комплект',
                'class': 'btn-outline-primary',
                'icon': 'box-seam'
            })

        if self.request.user.has_perm('products.add_configurableproduct'):
            action_buttons.append({
                'url': reverse_lazy('products:configurableproduct-create'),
                'text': 'Создать вариативный товар',
                'class': 'btn-outline-success',
                'icon': 'grid-3x3-gap'
            })

        if self.request.user.has_perm('products.add_productvariantgroup'):
            action_buttons.append({
                'url': reverse_lazy('products:variantgroup-create'),
                'text': 'Создать группу вариантов',
                'class': 'btn-outline-info',
                'icon': 'collection'
            })

        context['action_buttons'] = action_buttons

        return context
