"""
Views для управления отметками объектов.
"""

from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Prefetch
from django.http import JsonResponse
from django.views.generic import ListView, View
from django.shortcuts import get_object_or_404

from mainapp.models import Source, ObjectMark, CustomUser, Satellite


class ObjectMarksListView(LoginRequiredMixin, ListView):
    """
    Представление списка источников с отметками.
    """
    model = Source
    template_name = "mainapp/object_marks.html"
    context_object_name = "sources"
    
    def get_paginate_by(self, queryset):
        """Получить количество элементов на странице из параметров запроса"""
        from mainapp.utils import parse_pagination_params
        _, items_per_page = parse_pagination_params(self.request, default_per_page=50)
        return items_per_page

    def get_queryset(self):
        """Получить queryset с предзагруженными связанными данными"""
        from django.db.models import Count, Max, Min
        
        # Проверяем, выбран ли спутник
        satellite_id = self.request.GET.get('satellite_id')
        if not satellite_id:
            # Если спутник не выбран, возвращаем пустой queryset
            return Source.objects.none()
        
        queryset = Source.objects.prefetch_related(
            'source_objitems',
            'source_objitems__parameter_obj',
            'source_objitems__parameter_obj__id_satellite',
            'source_objitems__parameter_obj__polarization',
            'source_objitems__parameter_obj__modulation',
            Prefetch(
                'marks',
                queryset=ObjectMark.objects.select_related('created_by__user').order_by('-timestamp')
            )
        ).annotate(
            mark_count=Count('marks'),
            last_mark_date=Max('marks__timestamp'),
            # Аннотации для сортировки по параметрам (берем минимальное значение из связанных объектов)
            min_frequency=Min('source_objitems__parameter_obj__frequency'),
            min_freq_range=Min('source_objitems__parameter_obj__freq_range'),
            min_bod_velocity=Min('source_objitems__parameter_obj__bod_velocity')
        )
        
        # Фильтрация по выбранному спутнику (обязательно)
        queryset = queryset.filter(source_objitems__parameter_obj__id_satellite_id=satellite_id).distinct()
        
        # Фильтрация по статусу (есть/нет отметок)
        mark_status = self.request.GET.get('mark_status')
        if mark_status == 'with_marks':
            queryset = queryset.filter(mark_count__gt=0)
        elif mark_status == 'without_marks':
            queryset = queryset.filter(mark_count=0)
        
        # Фильтрация по дате отметки
        date_from = self.request.GET.get('date_from')
        date_to = self.request.GET.get('date_to')
        if date_from:
            from django.utils.dateparse import parse_date
            parsed_date = parse_date(date_from)
            if parsed_date:
                queryset = queryset.filter(marks__timestamp__date__gte=parsed_date).distinct()
        if date_to:
            from django.utils.dateparse import parse_date
            parsed_date = parse_date(date_to)
            if parsed_date:
                queryset = queryset.filter(marks__timestamp__date__lte=parsed_date).distinct()
        
        # Фильтрация по пользователям (мультивыбор)
        user_ids = self.request.GET.getlist('user_id')
        if user_ids:
            queryset = queryset.filter(marks__created_by_id__in=user_ids).distinct()
        
        # Поиск по имени объекта или ID
        search_query = self.request.GET.get('search', '').strip()
        if search_query:
            from django.db.models import Q
            try:
                # Попытка поиска по ID
                source_id = int(search_query)
                queryset = queryset.filter(Q(id=source_id) | Q(source_objitems__name__icontains=search_query)).distinct()
            except ValueError:
                # Поиск только по имени
                queryset = queryset.filter(source_objitems__name__icontains=search_query).distinct()
        
        # Сортировка
        sort = self.request.GET.get('sort', '-id')
        allowed_sorts = [
            'id', '-id', 
            'created_at', '-created_at', 
            'last_mark_date', '-last_mark_date', 
            'mark_count', '-mark_count',
            'frequency', '-frequency',
            'freq_range', '-freq_range',
            'bod_velocity', '-bod_velocity'
        ]
        
        if sort in allowed_sorts:
            # Для сортировки по last_mark_date нужно обработать NULL значения
            if 'last_mark_date' in sort:
                from django.db.models import F
                from django.db.models.functions import Coalesce
                queryset = queryset.order_by(
                    Coalesce(F('last_mark_date'), F('created_at')).desc() if sort.startswith('-') else Coalesce(F('last_mark_date'), F('created_at')).asc()
                )
            # Сортировка по частоте
            elif sort == 'frequency':
                queryset = queryset.order_by('min_frequency')
            elif sort == '-frequency':
                queryset = queryset.order_by('-min_frequency')
            # Сортировка по полосе
            elif sort == 'freq_range':
                queryset = queryset.order_by('min_freq_range')
            elif sort == '-freq_range':
                queryset = queryset.order_by('-min_freq_range')
            # Сортировка по бодовой скорости
            elif sort == 'bod_velocity':
                queryset = queryset.order_by('min_bod_velocity')
            elif sort == '-bod_velocity':
                queryset = queryset.order_by('-min_bod_velocity')
            else:
                queryset = queryset.order_by(sort)
        else:
            queryset = queryset.order_by('-id')
        
        return queryset
    
    def get_context_data(self, **kwargs):
        """Добавить дополнительные данные в контекст"""
        context = super().get_context_data(**kwargs)
        from mainapp.utils import parse_pagination_params
        
        # Все спутники для выбора
        context['satellites'] = Satellite.objects.filter(
            parameters__objitem__source__isnull=False
        ).distinct().order_by('name')
        
        # Выбранный спутник
        satellite_id = self.request.GET.get('satellite_id')
        context['selected_satellite_id'] = int(satellite_id) if satellite_id and satellite_id.isdigit() else None
        
        context['users'] = CustomUser.objects.select_related('user').filter(
            marks_created__isnull=False
        ).distinct().order_by('user__username')
        
        # Параметры пагинации
        page_number, items_per_page = parse_pagination_params(self.request, default_per_page=50)
        context['items_per_page'] = items_per_page
        context['available_items_per_page'] = [25, 50, 100, 200, 500]
        
        # Параметры поиска и сортировки
        context['search_query'] = self.request.GET.get('search', '')
        context['sort'] = self.request.GET.get('sort', '-id')
        
        # Параметры фильтров для отображения в UI
        context['selected_users'] = [int(x) for x in self.request.GET.getlist('user_id') if x.isdigit()]
        context['filter_mark_status'] = self.request.GET.get('mark_status', '')
        context['filter_date_from'] = self.request.GET.get('date_from', '')
        context['filter_date_to'] = self.request.GET.get('date_to', '')
        
        # Полноэкранный режим
        context['full_width_page'] = True
        
        # Добавить информацию о параметрах для каждого источника
        for source in context['sources']:
            # Получить первый объект для параметров (они должны быть одинаковыми)
            first_objitem = source.source_objitems.select_related(
                'parameter_obj',
                'parameter_obj__polarization',
                'parameter_obj__modulation'
            ).first()
            
            if first_objitem:
                source.objitem_name = first_objitem.name if first_objitem.name else '-'
                
                # Получить параметры
                if first_objitem.parameter_obj:
                    param = first_objitem.parameter_obj
                    source.frequency = param.frequency if param.frequency else '-'
                    source.freq_range = param.freq_range if param.freq_range else '-'
                    source.polarization = param.polarization.name if param.polarization else '-'
                    source.modulation = param.modulation.name if param.modulation else '-'
                    source.bod_velocity = param.bod_velocity if param.bod_velocity else '-'
                else:
                    source.frequency = '-'
                    source.freq_range = '-'
                    source.polarization = '-'
                    source.modulation = '-'
                    source.bod_velocity = '-'
            else:
                source.objitem_name = '-'
                source.frequency = '-'
                source.freq_range = '-'
                source.polarization = '-'
                source.modulation = '-'
                source.bod_velocity = '-'
            
            # Проверка возможности редактирования отметок
            for mark in source.marks.all():
                mark.editable = mark.can_edit()
        
        return context



class AddObjectMarkView(LoginRequiredMixin, View):
    """
    API endpoint для добавления отметки источника.
    """
    
    def post(self, request, *args, **kwargs):
        """Создать новую отметку"""
        from datetime import timedelta
        from django.utils import timezone
        
        source_id = request.POST.get('source_id')
        mark = request.POST.get('mark') == 'true'
        
        if not source_id:
            return JsonResponse({'success': False, 'error': 'Не указан ID источника'}, status=400)
        
        source = get_object_or_404(Source, pk=source_id)
        
        # Проверить последнюю отметку источника
        last_mark = source.marks.first()
        if last_mark:
            time_diff = timezone.now() - last_mark.timestamp
            if time_diff < timedelta(minutes=5):
                minutes_left = 5 - int(time_diff.total_seconds() / 60)
                return JsonResponse({
                    'success': False, 
                    'error': f'Нельзя добавить отметку. Подождите ещё {minutes_left} мин.'
                }, status=400)
        
        # Получить или создать CustomUser для текущего пользователя
        custom_user, _ = CustomUser.objects.get_or_create(user=request.user)
        
        # Создать отметку
        object_mark = ObjectMark.objects.create(
            source=source,
            mark=mark,
            created_by=custom_user
        )
        
        # Обновляем дату последнего сигнала источника
        source.update_last_signal_at()
        source.save()
        
        return JsonResponse({
            'success': True,
            'mark': {
                'id': object_mark.id,
                'mark': object_mark.mark,
                'timestamp': object_mark.timestamp.strftime('%d.%m.%Y %H:%M'),
                'created_by': str(object_mark.created_by) if object_mark.created_by else 'Неизвестно',
                'can_edit': object_mark.can_edit()
            }
        })


class UpdateObjectMarkView(LoginRequiredMixin, View):
    """
    API endpoint для обновления отметки объекта (в течение 5 минут).
    """
    
    def post(self, request, *args, **kwargs):
        """Обновить существующую отметку"""
        mark_id = request.POST.get('mark_id')
        new_mark_value = request.POST.get('mark') == 'true'
        
        if not mark_id:
            return JsonResponse({'success': False, 'error': 'Не указан ID отметки'}, status=400)
        
        object_mark = get_object_or_404(ObjectMark, pk=mark_id)
        
        # Проверить возможность редактирования
        if not object_mark.can_edit():
            return JsonResponse({
                'success': False, 
                'error': 'Время редактирования истекло (более 5 минут)'
            }, status=400)
        
        # Обновить отметку
        object_mark.mark = new_mark_value
        object_mark.save()
        
        # Обновляем дату последнего сигнала источника
        object_mark.source.update_last_signal_at()
        object_mark.source.save()
        
        return JsonResponse({
            'success': True,
            'mark': {
                'id': object_mark.id,
                'mark': object_mark.mark,
                'timestamp': object_mark.timestamp.strftime('%d.%m.%Y %H:%M'),
                'created_by': str(object_mark.created_by) if object_mark.created_by else 'Неизвестно',
                'can_edit': object_mark.can_edit()
            }
        })
