# -*- coding: utf-8 -*-
"""
Views для управления скидками и промокодами во фронтенде.

Права доступа:
- owner/manager/superuser - полный CRUD
- florist - только просмотр
- courier - нет доступа
"""
from django.views.generic import ListView, CreateView, UpdateView, DeleteView, TemplateView
from django.shortcuts import redirect, get_object_or_404
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
from django.utils.decorators import method_decorator
from django.core.exceptions import PermissionDenied
from django.db.models import Q, Count

from user_roles.mixins import RoleRequiredMixin
from user_roles.services import RoleService

from .models import Discount, PromoCode


class DiscountAccessMixin(RoleRequiredMixin):
    """
    Миксин для контроля доступа к скидкам.

    - owner/manager/superuser - полный CRUD
    - florist - только просмотр
    - courier - нет доступа
    """
    required_roles = ['owner', 'manager', 'florist']

    def dispatch(self, request, *args, **kwargs):
        # Superuser имеет полный доступ
        if request.user.is_superuser:
            return super().dispatch(request, *args, **kwargs)

        # Проверяем базовый доступ к роли
        if not RoleService.user_has_role(request.user, *self.required_roles):
            raise PermissionDenied("У вас нет прав для доступа к этой странице")

        # Florist - только просмотр списков
        if RoleService.user_has_role(request.user, 'florist'):
            # Разрешаем только ListView
            if not isinstance(self, ListView):
                raise PermissionDenied("Флористы могут только просматривать скидки")

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


class DiscountListView(DiscountAccessMixin, ListView):
    """Список скидок"""
    model = Discount
    template_name = 'discounts/discount_list.html'
    context_object_name = 'discounts'
    paginate_by = 20

    def get_queryset(self):
        queryset = Discount.objects.select_related(
            'created_by'
        ).prefetch_related(
            'products', 'categories'
        ).annotate(
            promo_count=Count('promo_codes')
        ).order_by('-created_at')

        # Фильтры
        discount_type = self.request.GET.get('type')
        scope = self.request.GET.get('scope')
        is_active = self.request.GET.get('is_active')
        combine_mode = self.request.GET.get('combine_mode')
        search = self.request.GET.get('search')

        if discount_type:
            queryset = queryset.filter(discount_type=discount_type)
        if scope:
            queryset = queryset.filter(scope=scope)
        if is_active:
            queryset = queryset.filter(is_active=(is_active == 'active'))
        if combine_mode:
            queryset = queryset.filter(combine_mode=combine_mode)
        if search:
            queryset = queryset.filter(
                Q(name__icontains=search) | Q(description__icontains=search)
            )

        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['current_filters'] = {
            'type': self.request.GET.get('type', ''),
            'scope': self.request.GET.get('scope', ''),
            'is_active': self.request.GET.get('is_active', ''),
            'combine_mode': self.request.GET.get('combine_mode', ''),
            'search': self.request.GET.get('search', ''),
        }
        context['can_edit'] = self._can_edit()
        return context

    def _can_edit(self):
        """Проверка прав на редактирование"""
        if self.request.user.is_superuser:
            return True
        return RoleService.user_has_role(self.request.user, 'owner', 'manager')


class DiscountCreateView(LoginRequiredMixin, RoleRequiredMixin, CreateView):
    """Создание скидки (только owner/manager)"""
    model = Discount
    template_name = 'discounts/discount_form.html'
    fields = [
        'name', 'description', 'discount_type', 'value', 'scope',
        'is_auto', 'is_active', 'priority', 'combine_mode',
        'start_date', 'end_date',
        'min_order_amount', 'max_usage_count',
        'products', 'categories', 'excluded_products',
    ]
    required_roles = ['owner', 'manager']
    success_url = reverse_lazy('system_settings:discounts:list')

    def form_valid(self, form):
        # Валидация: нельзя создать больше одной активной exclusive скидки на заказ
        if form.instance.combine_mode == 'exclusive' and form.instance.scope == 'order' and form.instance.is_active:
            existing_exclusive = Discount.objects.filter(
                combine_mode='exclusive',
                scope='order',
                is_active=True
            ).exists()

            if existing_exclusive:
                form.add_error(
                    'combine_mode',
                    'Уже существует активная исключающая скидка на заказ. Может быть только одна.'
                )
                return self.form_invalid(form)

        form.instance.created_by = self.request.user
        messages.success(self.request, f'Скидка "{form.instance.name}" создана')
        return super().form_valid(form)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['is_edit'] = False
        # Передаем товары и категории для формы
        from products.models import Product, ProductCategory
        context['all_products'] = Product.objects.filter(status='active').order_by('name')
        context['all_categories'] = ProductCategory.objects.filter(is_active=True).order_by('name')
        context['selected_products'] = []
        context['selected_categories'] = []
        context['excluded_products'] = []
        return context


class DiscountUpdateView(LoginRequiredMixin, RoleRequiredMixin, UpdateView):
    """Редактирование скидки (только owner/manager)"""
    model = Discount
    template_name = 'discounts/discount_form.html'
    fields = [
        'name', 'description', 'discount_type', 'value', 'scope',
        'is_auto', 'is_active', 'priority', 'combine_mode',
        'start_date', 'end_date',
        'min_order_amount', 'max_usage_count',
        'products', 'categories', 'excluded_products',
    ]
    required_roles = ['owner', 'manager']
    success_url = reverse_lazy('system_settings:discounts:list')

    def form_valid(self, form):
        # Валидация: нельзя создать больше одной активной exclusive скидки на заказ
        if form.instance.combine_mode == 'exclusive' and form.instance.scope == 'order' and form.instance.is_active:
            existing_exclusive = Discount.objects.filter(
                combine_mode='exclusive',
                scope='order',
                is_active=True
            ).exclude(pk=self.object.pk).exists()

            if existing_exclusive:
                form.add_error(
                    'combine_mode',
                    'Уже существует активная исключающая скидка на заказ. Может быть только одна.'
                )
                return self.form_invalid(form)

        messages.success(self.request, f'Скидка "{form.instance.name}" обновлена')
        return super().form_valid(form)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['is_edit'] = True
        # Передаем товары и категории для формы
        from products.models import Product, ProductCategory
        context['all_products'] = Product.objects.filter(status='active').order_by('name')
        context['all_categories'] = ProductCategory.objects.filter(is_active=True).order_by('name')
        context['selected_products'] = list(self.object.products.values_list('id', flat=True))
        context['selected_categories'] = list(self.object.categories.values_list('id', flat=True))
        context['excluded_products'] = list(self.object.excluded_products.values_list('id', flat=True))
        return context


class DiscountDeleteView(LoginRequiredMixin, RoleRequiredMixin, DeleteView):
    """Удаление скидки (только owner/manager)"""
    model = Discount
    template_name = 'discounts/discount_confirm_delete.html'
    required_roles = ['owner', 'manager']
    success_url = reverse_lazy('system_settings:discounts:list')

    def delete(self, request, *args, **kwargs):
        obj = self.get_object()
        messages.success(self.request, f'Скидка "{obj.name}" удалена')
        return super().delete(request, *args, **kwargs)


@login_required
def discount_toggle(request, pk):
    """Переключение активности скидки (только owner/manager)"""
    if not request.user.is_superuser and not RoleService.user_has_role(request.user, 'owner', 'manager'):
        raise PermissionDenied("У вас нет прав для этого действия")

    discount = get_object_or_404(Discount, pk=pk)
    discount.is_active = not discount.is_active
    discount.save(update_fields=['is_active'])

    status = "активирована" if discount.is_active else "деактивирована"
    messages.success(request, f'Скидка "{discount.name}" {status}')
    return redirect('system_settings:discounts:list')


# ============== Промокоды ==============

class PromoCodeAccessMixin(RoleRequiredMixin):
    """Миксин для контроля доступа к промокодам"""
    required_roles = ['owner', 'manager', 'florist']

    def dispatch(self, request, *args, **kwargs):
        if request.user.is_superuser:
            return super().dispatch(request, *args, **kwargs)

        if not RoleService.user_has_role(request.user, *self.required_roles):
            raise PermissionDenied("У вас нет прав для доступа к этой странице")

        # Florist - только просмотр
        if RoleService.user_has_role(request.user, 'florist'):
            if not isinstance(self, ListView):
                raise PermissionDenied("Флористы могут только просматривать промокоды")

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


class PromoCodeListView(PromoCodeAccessMixin, ListView):
    """Список промокодов"""
    model = PromoCode
    template_name = 'discounts/promocode_list.html'
    context_object_name = 'promocodes'
    paginate_by = 20

    def get_queryset(self):
        queryset = PromoCode.objects.select_related(
            'discount', 'created_by'
        ).order_by('-created_at')

        # Фильтры
        is_active = self.request.GET.get('is_active')
        search = self.request.GET.get('search')

        if is_active:
            queryset = queryset.filter(is_active=(is_active == 'active'))
        if search:
            queryset = queryset.filter(code__icontains=search)

        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['current_filters'] = {
            'is_active': self.request.GET.get('is_active', ''),
            'search': self.request.GET.get('search', ''),
        }
        context['can_edit'] = self._can_edit()
        return context

    def _can_edit(self):
        if self.request.user.is_superuser:
            return True
        return RoleService.user_has_role(self.request.user, 'owner', 'manager')


class PromoCodeCreateView(LoginRequiredMixin, RoleRequiredMixin, CreateView):
    """Создание промокода (только owner/manager)"""
    model = PromoCode
    template_name = 'discounts/promocode_form.html'
    fields = [
        'code', 'discount', 'is_active',
        'start_date', 'end_date',
        'max_uses_per_user', 'max_total_uses',
    ]
    required_roles = ['owner', 'manager']
    success_url = reverse_lazy('system_settings:discounts:promo-list')

    def form_valid(self, form):
        form.instance.created_by = self.request.user
        messages.success(self.request, f'Промокод "{form.instance.code}" создан')
        return super().form_valid(form)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['is_edit'] = False
        # Передаем активные скидки для выбора
        context['all_discounts'] = Discount.objects.filter(is_active=True).order_by('name')
        return context


class PromoCodeUpdateView(LoginRequiredMixin, RoleRequiredMixin, UpdateView):
    """Редактирование промокода (только owner/manager)"""
    model = PromoCode
    template_name = 'discounts/promocode_form.html'
    fields = [
        'code', 'discount', 'is_active',
        'start_date', 'end_date',
        'max_uses_per_user', 'max_total_uses',
    ]
    required_roles = ['owner', 'manager']
    success_url = reverse_lazy('system_settings:discounts:promo-list')

    def form_valid(self, form):
        messages.success(self.request, f'Промокод "{form.instance.code}" обновлён')
        return super().form_valid(form)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['is_edit'] = True
        # Передаем все скидки для выбора (включая неактивные, если они выбраны)
        context['all_discounts'] = Discount.objects.all().order_by('name')
        return context


class PromoCodeDeleteView(LoginRequiredMixin, RoleRequiredMixin, DeleteView):
    """Удаление промокода (только owner/manager)"""
    model = PromoCode
    template_name = 'discounts/promocode_confirm_delete.html'
    required_roles = ['owner', 'manager']
    success_url = reverse_lazy('system_settings:discounts:promo-list')

    def delete(self, request, *args, **kwargs):
        obj = self.get_object()
        messages.success(self.request, f'Промокод "{obj.code}" удалён')
        return super().delete(request, *args, **kwargs)


@login_required
def promocode_toggle(request, pk):
    """Переключение активности промокода (только owner/manager)"""
    if not request.user.is_superuser and not RoleService.user_has_role(request.user, 'owner', 'manager'):
        raise PermissionDenied("У вас нет прав для этого действия")

    promocode = get_object_or_404(PromoCode, pk=pk)
    promocode.is_active = not promocode.is_active
    promocode.save(update_fields=['is_active'])

    status = "активирован" if promocode.is_active else "деактивирован"
    messages.success(request, f'Промокод "{promocode.code}" {status}')
    return redirect('system_settings:discounts:promo-list')
