"""
CRUD представления для комплектов товаров (ProductKit).
"""
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.shortcuts import redirect
from django.db import transaction, IntegrityError

from user_roles.mixins import ManagerOwnerRequiredMixin
from ..models import ProductKit, ProductCategory, ProductTag, ProductKitPhoto, Product, ProductVariantGroup
from ..forms import ProductKitForm, KitItemFormSetCreate, KitItemFormSetUpdate
from .utils import handle_photos


class ProductKitListView(LoginRequiredMixin, ManagerOwnerRequiredMixin, ListView):
    model = ProductKit
    template_name = 'products/productkit_list.html'
    context_object_name = 'kits'
    paginate_by = 10

    def get_queryset(self):
        queryset = super().get_queryset()
        queryset = queryset.prefetch_related('categories', 'photos', 'kit_items', 'tags')

        # Скрываем временные комплекты из общего каталога
        queryset = queryset.filter(is_temporary=False)

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

        # Фильтр по категории
        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 = self.request.GET.get('is_active')
            if is_active == '1':
                queryset = queryset.filter(status='active')
            elif is_active == '0':
                queryset = queryset.filter(status__in=['archived', 'discontinued'])

        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', ''),
                'is_active': self.request.GET.get('is_active', ''),
                'tags': self.request.GET.getlist('tags'),
            }
        }

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

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

        action_buttons.append({
            'url': reverse_lazy('products:products-list'),
            'text': 'К товарам',
            'class': 'btn-outline-primary',
            'icon': 'box'
        })

        context['action_buttons'] = action_buttons

        return context


class ProductKitCreateView(LoginRequiredMixin, ManagerOwnerRequiredMixin, CreateView):
    """
    View для создания нового комплекта с добавлением компонентов на одной странице.
    """
    model = ProductKit
    form_class = ProductKitForm
    template_name = 'products/productkit_create.html'

    def post(self, request, *args, **kwargs):
        """
        Обрабатываем POST данные и очищаем ID товаров/комплектов от префиксов.
        API возвращает ID в формате "product_123" или "kit_456", но Django ожидает числа.
        """
        # Создаем изменяемую копию POST данных
        post_data = request.POST.copy()

        # Очищаем product ID от префиксов (product_123 -> 123)
        for key in post_data.keys():
            if key.endswith('-product') and post_data[key]:
                value = post_data[key]
                if '_' in value:
                    # Извлекаем числовой ID из "product_123"
                    numeric_id = value.split('_')[1]
                    post_data[key] = numeric_id

        # Заменяем request.POST на очищенные данные
        request.POST = post_data

        return super().post(request, *args, **kwargs)

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

        if self.request.POST:
            context['kititem_formset'] = KitItemFormSetCreate(self.request.POST, prefix='kititem')

            # При ошибке валидации: извлекаем выбранные товары для предзагрузки в Select2
            from ..models import Product, ProductVariantGroup
            selected_products = {}
            selected_variants = {}

            for key, value in self.request.POST.items():
                if '-product' in key and value:
                    try:
                        product = Product.objects.get(id=value)
                        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
                        selected_products[key] = {
                            'id': product.id,
                            'text': text,
                            'price': str(product.price) if product.price else None,
                            'actual_price': str(actual_price) if actual_price else '0'
                        }
                    except Product.DoesNotExist:
                        pass

                if '-variant_group' in key and value:
                    try:
                        variant_group = ProductVariantGroup.objects.prefetch_related(
                            'items__product'
                        ).get(id=value)

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

                        selected_variants[key] = {
                            'id': variant_group.id,
                            'text': f"{variant_group.name} ({count} вариантов)",
                            'price': str(variant_price),
                            'actual_price': str(variant_price),
                            'type': 'variant',
                            'count': count
                        }
                    except ProductVariantGroup.DoesNotExist:
                        pass

            context['selected_products'] = selected_products
            context['selected_variants'] = selected_variants
        else:
            context['kititem_formset'] = KitItemFormSetCreate(prefix='kititem')

        return context

    def form_valid(self, form):
        # Получаем формсет из POST с правильным префиксом
        kititem_formset = KitItemFormSetCreate(self.request.POST, prefix='kititem')

        # Проверяем валидность основной формы
        if not form.is_valid():
            messages.error(self.request, 'Пожалуйста, исправьте ошибки в основной форме комплекта.')
            return self.form_invalid(form)

        if not kititem_formset.is_valid():
            # Если формсет невалиден, показываем форму с ошибками
            messages.error(self.request, 'Пожалуйста, исправьте ошибки в компонентах комплекта.')
            return self.form_invalid(form)

        try:
            with transaction.atomic():
                # Сохраняем основную форму (комплект)
                self.object = form.save(commit=True)

                # Убеждаемся что объект в БД
                if not self.object.pk:
                    raise Exception("Не удалось сохранить комплект в базу данных")

                # Сохраняем компоненты
                kititem_formset.instance = self.object
                saved_items = kititem_formset.save()

                # Пересчитываем базовую цену после сохранения всех компонентов
                self.object.recalculate_base_price()

                # Обработка фотографий
                handle_photos(self.request, self.object, ProductKitPhoto, 'kit')

                messages.success(
                    self.request,
                    f'Комплект "{self.object.name}" успешно создан!'
                )

                return redirect('products:products-list')
        except IntegrityError as e:
            # Обработка нарушения уникальности в БД
            error_msg = str(e).lower()
            if 'unique_active_kit_name' in error_msg or ('name' in error_msg and 'duplicate' in error_msg):
                messages.error(
                    self.request,
                    f'Ошибка: комплект с названием "{form.instance.name}" уже существует. '
                    'Пожалуйста, используйте другое название.'
                )
            elif 'slug' in error_msg or 'unique' in error_msg:
                messages.error(
                    self.request,
                    'Ошибка: комплект с таким названием уже существует. '
                    'Пожалуйста, используйте другое название.'
                )
            else:
                messages.error(
                    self.request,
                    'Ошибка при сохранении комплекта. Пожалуйста, проверьте введённые данные.'
                )
            return self.form_invalid(form)
        except Exception as e:
            messages.error(self.request, f'Ошибка при сохранении: {str(e)}')
            import traceback
            traceback.print_exc()
            return self.form_invalid(form)

    def form_invalid(self, form):
        # Получаем формсет для отображения ошибок
        context = self.get_context_data(form=form)
        return self.render_to_response(context)


class ProductKitUpdateView(LoginRequiredMixin, ManagerOwnerRequiredMixin, UpdateView):
    """
    View для редактирования существующего комплекта и добавления товаров.
    """
    model = ProductKit
    form_class = ProductKitForm
    template_name = 'products/productkit_edit.html'

    def post(self, request, *args, **kwargs):
        """
        Обрабатываем POST данные и очищаем ID товаров/комплектов от префиксов.
        API возвращает ID в формате "product_123" или "kit_456", но Django ожидает числа.
        """
        # Создаем изменяемую копию POST данных
        post_data = request.POST.copy()

        # Очищаем product ID от префиксов (product_123 -> 123)
        for key in post_data.keys():
            if key.endswith('-product') and post_data[key]:
                value = post_data[key]
                if '_' in value:
                    # Извлекаем числовой ID из "product_123"
                    numeric_id = value.split('_')[1]
                    post_data[key] = numeric_id

        # Заменяем request.POST на очищенные данные
        request.POST = post_data

        return super().post(request, *args, **kwargs)

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

        if self.request.POST:
            context['kititem_formset'] = KitItemFormSetUpdate(self.request.POST, instance=self.object, prefix='kititem')

            # При ошибке валидации - подготавливаем данные для Select2
            selected_products = {}
            selected_variants = {}

            for key, value in self.request.POST.items():
                if '-product' in key and value:
                    try:
                        # Очищаем ID от префикса если есть
                        numeric_value = value.split('_')[1] if '_' in value else value
                        product = Product.objects.get(id=numeric_value)

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

                        actual_price = product.sale_price if product.sale_price else product.price
                        selected_products[key] = {
                            'id': product.id,
                            'text': text,
                            'price': str(product.price) if product.price else None,
                            'actual_price': str(actual_price) if actual_price else '0'
                        }
                    except Product.DoesNotExist:
                        pass

                if '-variant_group' in key and value:
                    try:
                        variant_group = ProductVariantGroup.objects.prefetch_related(
                            'items__product'
                        ).get(id=value)

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

                        selected_variants[key] = {
                            'id': variant_group.id,
                            'text': f"{variant_group.name} ({count} вариантов)",
                            'price': str(variant_price),
                            'actual_price': str(variant_price),
                            'type': 'variant',
                            'count': count
                        }
                    except ProductVariantGroup.DoesNotExist:
                        pass

            context['selected_products'] = selected_products
            context['selected_variants'] = selected_variants
        else:
            context['kititem_formset'] = KitItemFormSetUpdate(instance=self.object, prefix='kititem')

            # Подготавливаем данные для предзагрузки в Select2
            selected_products = {}
            selected_variants = {}

            for item in self.object.kit_items.all():
                form_prefix = f"kititem-{item.id}"

                if item.product:
                    product = item.product
                    text = product.name
                    if product.sku:
                        text += f" ({product.sku})"

                    actual_price = product.sale_price if product.sale_price else product.price
                    selected_products[f"{form_prefix}-product"] = {
                        'id': product.id,
                        'text': text,
                        'price': str(product.price) if product.price else None,
                        'actual_price': str(actual_price) if actual_price else '0'
                    }

                if item.variant_group:
                    variant_group = ProductVariantGroup.objects.prefetch_related(
                        'items__product'
                    ).get(id=item.variant_group.id)

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

                    selected_variants[f"{form_prefix}-variant_group"] = {
                        'id': variant_group.id,
                        'text': f"{variant_group.name} ({count} вариантов)",
                        'price': str(variant_price),
                        'actual_price': str(variant_price),
                        'type': 'variant',
                        'count': count
                    }

            context['selected_products'] = selected_products
            context['selected_variants'] = selected_variants

        context['productkit_photos'] = self.object.photos.all().order_by('order', 'created_at')
        context['photos_count'] = self.object.photos.count()

        return context

    def form_valid(self, form):
        # Получаем формсет из POST с правильным префиксом
        kititem_formset = KitItemFormSetUpdate(self.request.POST, instance=self.object, prefix='kititem')

        # Проверяем валидность основной формы и формсета
        if not form.is_valid():
            messages.error(self.request, 'Пожалуйста, исправьте ошибки в основной форме комплекта.')
            return self.form_invalid(form)

        if not kititem_formset.is_valid():
            # Если формсет невалиден, показываем форму с ошибками
            messages.error(self.request, 'Пожалуйста, исправьте ошибки в компонентах комплекта.')
            return self.form_invalid(form)

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

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

                # Пересчитываем базовую цену после сохранения всех компонентов
                self.object.recalculate_base_price()

                # Обработка фотографий
                handle_photos(self.request, self.object, ProductKitPhoto, 'kit')

                messages.success(self.request, f'Комплект "{self.object.name}" успешно обновлен!')

                # Проверяем, какую кнопку нажали
                if self.request.POST.get('action') == 'continue':
                    return redirect('products:productkit-update', pk=self.object.pk)
                else:
                    return redirect('products:products-list')
        except IntegrityError as e:
            # Обработка нарушения уникальности в БД
            error_msg = str(e).lower()
            if 'unique_active_kit_name' in error_msg or ('name' in error_msg and 'duplicate' in error_msg):
                messages.error(
                    self.request,
                    f'Ошибка: комплект с названием "{form.instance.name}" уже существует. '
                    'Пожалуйста, используйте другое название.'
                )
            elif 'slug' in error_msg or 'unique' in error_msg:
                messages.error(
                    self.request,
                    'Ошибка: комплект с таким названием уже существует. '
                    'Пожалуйста, используйте другое название.'
                )
            else:
                messages.error(
                    self.request,
                    'Ошибка при сохранении комплекта. Пожалуйста, проверьте введённые данные.'
                )
            return self.form_invalid(form)
        except Exception as e:
            messages.error(self.request, f'Ошибка при сохранении: {str(e)}')
            import traceback
            traceback.print_exc()
            return self.form_invalid(form)

    def form_invalid(self, form):
        # Получаем формсет для отображения ошибок
        context = self.get_context_data(form=form)
        return self.render_to_response(context)

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


class ProductKitDetailView(LoginRequiredMixin, ManagerOwnerRequiredMixin, DetailView):
    """
    View для просмотра деталей комплекта.
    Показывает все компоненты, цены, фотографии.
    """
    model = ProductKit
    template_name = 'products/productkit_detail.html'
    context_object_name = 'kit'

    def get_queryset(self):
        # Prefetch для оптимизации запросов
        return super().get_queryset().prefetch_related(
            'photos',
            'kit_items__product',
            'kit_items__variant_group',
            'tags'
        )

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


class ProductKitDeleteView(LoginRequiredMixin, ManagerOwnerRequiredMixin, DeleteView):
    """
    View для удаления комплекта.
    """
    model = ProductKit
    template_name = 'products/productkit_confirm_delete.html'
    context_object_name = 'kit'

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


class ProductKitMakePermanentView(LoginRequiredMixin, ManagerOwnerRequiredMixin, UpdateView):
    """
    View для преобразования временного комплекта в постоянный.
    Позволяет отредактировать название, добавить категории, теги перед сохранением.
    """
    model = ProductKit
    template_name = 'products/productkit_make_permanent.html'
    context_object_name = 'kit'
    fields = ['name', 'description', 'categories', 'tags', 'sale_price']

    def get_queryset(self):
        # Только временные комплекты можно преобразовать
        return super().get_queryset().filter(is_temporary=True)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['kit_items'] = self.object.kit_items.all().select_related('product', 'variant_group')
        context['productkit_photos'] = self.object.photos.all().order_by('order', 'created_at')
        return context

    def form_valid(self, form):
        # Преобразуем в постоянный
        if self.object.make_permanent():
            messages.success(
                self.request,
                f'Комплект "{self.object.name}" преобразован в постоянный и теперь доступен в каталоге!'
            )
        else:
            messages.warning(self.request, f'Комплект "{self.object.name}" уже является постоянным.')

        return super().form_valid(form)

    def get_success_url(self):
        return reverse_lazy('products:productkit-detail', kwargs={'pk': self.object.pk})
