"""
CRUD представления для групп вариантов товаров (ProductVariantGroup).
Включает управление товарами в группе с приоритизацией.
"""
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.decorators import login_required
from django.views.generic import ListView, CreateView, DetailView, UpdateView, DeleteView
from django.urls import reverse_lazy, reverse
from django.shortcuts import redirect, get_object_or_404
from django.http import JsonResponse
from django.db.models import Q, Count
from django.db import transaction
from django.views.decorators.http import require_http_methods

from ..models import ProductVariantGroup, ProductVariantGroupItem
from ..forms import (
    ProductVariantGroupForm,
    ProductVariantGroupItemFormSetCreate,
    ProductVariantGroupItemFormSetUpdate
)


class ProductVariantGroupListView(LoginRequiredMixin, ListView):
    """Список всех групп вариантов с поиском и фильтрацией"""
    model = ProductVariantGroup
    template_name = 'products/variantgroup_list.html'
    context_object_name = 'variant_groups'
    paginate_by = 20

    def get_queryset(self):
        queryset = super().get_queryset()

        # Оптимизация: загружаем товары для вычисления in_stock и price
        queryset = queryset.prefetch_related('items__product')

        # Добавляем количество товаров в каждую группу
        queryset = queryset.annotate(items_count=Count('items'))

        # Поиск по названию и описанию
        search_query = self.request.GET.get('search')
        if search_query:
            queryset = queryset.filter(
                Q(name__icontains=search_query) |
                Q(description__icontains=search_query)
            )

        return queryset.order_by('-updated_at')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['search_query'] = self.request.GET.get('search', '')
        return context


class ProductVariantGroupCreateView(LoginRequiredMixin, CreateView):
    """Создание новой группы вариантов с добавлением товаров"""
    model = ProductVariantGroup
    form_class = ProductVariantGroupForm
    template_name = 'products/variantgroup_form.html'
    success_url = reverse_lazy('products:variantgroup-list')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        if self.request.POST:
            context['items_formset'] = ProductVariantGroupItemFormSetCreate(
                self.request.POST,
                prefix='items'
            )
        else:
            context['items_formset'] = ProductVariantGroupItemFormSetCreate(
                prefix='items'
            )
        context['is_create'] = True
        return context

    def form_valid(self, form):
        """Сохраняем группу и товары в одной транзакции"""
        items_formset = ProductVariantGroupItemFormSetCreate(
            self.request.POST,
            prefix='items'
        )

        # Проверяем валидность основной формы и формсета
        if not form.is_valid() or not items_formset.is_valid():
            return self.form_invalid(form)

        try:
            with transaction.atomic():
                # Сохраняем группу
                self.object = form.save(commit=True)

                # Сохраняем товары
                items_formset.instance = self.object
                items_formset.save()

                # Пересчитываем приоритеты
                self._recalculate_priorities(self.object)

                messages.success(
                    self.request,
                    f'Группа вариантов "{self.object.name}" успешно создана!'
                )
                return redirect('products:variantgroup-list')
        except Exception as e:
            messages.error(self.request, f'Ошибка при сохранении: {str(e)}')
            return self.form_invalid(form)

    @staticmethod
    def _recalculate_priorities(variant_group):
        """Пересчитывает приоритеты товаров в группе (по порядку в БД)"""
        items = variant_group.items.all().order_by('id')
        for idx, item in enumerate(items, start=1):
            item.priority = idx
            item.save(update_fields=['priority'])


class ProductVariantGroupDetailView(LoginRequiredMixin, DetailView):
    """Просмотр группы вариантов с список товаров в ней"""
    model = ProductVariantGroup
    template_name = 'products/variantgroup_detail.html'
    context_object_name = 'variant_group'

    def get_queryset(self):
        queryset = super().get_queryset()
        return queryset.prefetch_related('items__product')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # Используем уже загруженные товары из prefetch_related
        # без создания нового queryset для оптимизации БД
        context['items'] = sorted(
            self.object.items.all(),
            key=lambda item: (item.priority, item.id)
        )
        return context


class ProductVariantGroupUpdateView(LoginRequiredMixin, UpdateView):
    """Редактирование группы вариантов и управление товарами в ней"""
    model = ProductVariantGroup
    form_class = ProductVariantGroupForm
    template_name = 'products/variantgroup_form.html'
    success_url = reverse_lazy('products:variantgroup-list')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        if self.request.POST:
            context['items_formset'] = ProductVariantGroupItemFormSetUpdate(
                self.request.POST,
                instance=self.object,
                prefix='items'
            )
        else:
            context['items_formset'] = ProductVariantGroupItemFormSetUpdate(
                instance=self.object,
                prefix='items'
            )
        context['is_create'] = False
        return context

    def form_valid(self, form):
        """Сохраняем изменения группы и товаров"""
        items_formset = ProductVariantGroupItemFormSetUpdate(
            self.request.POST,
            instance=self.object,
            prefix='items'
        )

        if not form.is_valid() or not items_formset.is_valid():
            return self.form_invalid(form)

        try:
            with transaction.atomic():
                self.object = form.save(commit=True)
                items_formset.instance = self.object
                # Сохраняем формсет, который содержит приоритеты установленные пользователем
                items_formset.save()

                messages.success(
                    self.request,
                    f'Группа вариантов "{self.object.name}" успешно обновлена!'
                )
                return redirect('products:variantgroup-list')
        except Exception as e:
            messages.error(self.request, f'Ошибка при сохранении: {str(e)}')
            return self.form_invalid(form)


class ProductVariantGroupDeleteView(LoginRequiredMixin, DeleteView):
    """Удаление группы вариантов с подтверждением"""
    model = ProductVariantGroup
    template_name = 'products/variantgroup_confirm_delete.html'
    success_url = reverse_lazy('products:variantgroup-list')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # Добавляем информацию о товарах в группе
        context['items'] = self.object.items.all().select_related('product').order_by('priority')
        context['items_count'] = context['items'].count()
        return context

    def delete(self, request, *args, **kwargs):
        """Удаляем группу и показываем сообщение об успехе"""
        group_name = self.get_object().name
        response = super().delete(request, *args, **kwargs)
        messages.success(request, f'Группа вариантов "{group_name}" успешно удалена!')
        return response


@require_http_methods(["POST"])
@login_required
def product_variant_group_item_move(request, item_id, direction):
    """
    AJAX view для перемещения товара вверх/вниз в группе (UP/DOWN кнопки).
    Перемещает товар вверх (up) или вниз (down) в списке приоритетов.
    Автоматически пересчитывает приоритеты.
    """
    try:
        # Получаем товар в группе
        item = get_object_or_404(ProductVariantGroupItem, pk=item_id)
        variant_group = item.variant_group

        # Получаем все товары в группе отсортированные по приоритету
        all_items = list(
            variant_group.items.all()
            .order_by('priority')
            .values_list('id', 'priority')
        )

        # Находим текущую позицию товара
        current_index = next(
            (idx for idx, (item_pk, _) in enumerate(all_items) if item_pk == item_id),
            None
        )

        if current_index is None:
            return JsonResponse({'error': 'Товар не найден'}, status=404)

        # Перемещаем товар
        if direction == 'up' and current_index > 0:
            # Меняем местами с товаром выше
            all_items[current_index], all_items[current_index - 1] = \
                all_items[current_index - 1], all_items[current_index]
        elif direction == 'down' and current_index < len(all_items) - 1:
            # Меняем местами с товаром ниже
            all_items[current_index], all_items[current_index + 1] = \
                all_items[current_index + 1], all_items[current_index]
        else:
            # Товар уже в крайней позиции
            return JsonResponse({
                'error': f'Товар уже в крайней позиции',
                'items': _get_items_data(variant_group)
            }, status=400)

        # Пересчитываем приоритеты
        with transaction.atomic():
            for idx, (item_pk, _) in enumerate(all_items, start=1):
                ProductVariantGroupItem.objects.filter(pk=item_pk).update(priority=idx)

        # Возвращаем обновленный список товаров
        return JsonResponse({
            'success': True,
            'message': f'Товар перемещен',
            'items': _get_items_data(variant_group)
        })

    except Exception as e:
        return JsonResponse({'error': str(e)}, status=500)


def _get_items_data(variant_group):
    """Возвращает данные о товарах для обновления таблицы после AJAX операций"""
    items = variant_group.items.all().select_related('product').order_by('priority')
    items_data = []
    for item in items:
        items_data.append({
            'id': item.id,
            'product_name': item.product.name,
            'product_sku': item.product.sku,
            'product_price': str(item.product.actual_price),
            'priority': item.priority,
            'can_move_up': item.priority > 1,
            'can_move_down': item.priority < items.count()
        })
    return items_data
