"""
Представления для страницы Кубсат с фильтрацией и экспортом в Excel
"""
from datetime import datetime
from io import BytesIO

from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.gis.geos import Point
from django.db.models import Count, Q
from django.http import HttpResponse
from django.views.generic import FormView
from openpyxl import Workbook
from openpyxl.styles import Font, Alignment

from mainapp.forms import KubsatFilterForm
from mainapp.models import Source, ObjItem
from mainapp.permissions import PermissionRequiredMixin
from mainapp.utils import calculate_mean_coords


class KubsatView(LoginRequiredMixin, PermissionRequiredMixin, FormView):
    """Страница Кубсат с фильтрами и таблицей источников"""
    permission_required = 'kubsat_view'
    template_name = 'mainapp/kubsat_tabs.html'
    form_class = KubsatFilterForm
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['full_width_page'] = True
        
        # Добавляем данные для вкладки заявок
        from mainapp.models import SourceRequest, Satellite
        
        # Список спутников для формы создания заявки
        context['satellites'] = Satellite.objects.all().order_by('name')
        
        requests_qs = SourceRequest.objects.select_related(
            'source', 'source__info', 'source__ownership',
            'satellite',
            'created_by__user', 'updated_by__user'
        ).prefetch_related(
            'source__source_objitems__parameter_obj__modulation'
        ).order_by('-created_at')
        
        # Фильтры для заявок
        status = self.request.GET.get('status')
        if status:
            requests_qs = requests_qs.filter(status=status)
        
        priority = self.request.GET.get('priority')
        if priority:
            requests_qs = requests_qs.filter(priority=priority)
        
        # Добавляем данные источника к каждой заявке
        requests_list = []
        for req in requests_qs[:100]:
            # Получаем данные из первой точки источника
            objitem_name = '-'
            modulation = '-'
            symbol_rate = '-'
            
            if req.source:
                first_objitem = req.source.source_objitems.select_related(
                    'parameter_obj__modulation'
                ).order_by('geo_obj__timestamp').first()
                
                if first_objitem:
                    objitem_name = first_objitem.name or '-'
                    if first_objitem.parameter_obj:
                        if first_objitem.parameter_obj.modulation:
                            modulation = first_objitem.parameter_obj.modulation.name
                        if first_objitem.parameter_obj.bod_velocity and first_objitem.parameter_obj.bod_velocity > 0:
                            symbol_rate = str(int(first_objitem.parameter_obj.bod_velocity))
            
            # Добавляем атрибуты к объекту заявки
            req.objitem_name = objitem_name
            req.modulation = modulation
            req.symbol_rate = symbol_rate
            requests_list.append(req)
        
        context['requests'] = requests_list
        
        # Сериализуем заявки в JSON для Tabulator
        import json
        from django.utils import timezone
        
        requests_json_data = []
        for req in requests_list:
            # Конвертируем даты в локальный часовой пояс для отображения
            planned_at_local = None
            planned_at_iso = None
            if req.planned_at:
                planned_at_local = timezone.localtime(req.planned_at)
                planned_at_iso = planned_at_local.isoformat()
            
            requests_json_data.append({
                'id': req.id,
                'source_id': req.source_id,
                'satellite_name': req.satellite.name if req.satellite else '-',
                'status': req.status,
                'status_display': req.get_status_display(),
                'priority': req.priority,
                'priority_display': req.get_priority_display(),
                # Даты в ISO формате для правильной сортировки
                'request_date': req.request_date.isoformat() if req.request_date else None,
                'card_date': req.card_date.isoformat() if req.card_date else None,
                'planned_at': planned_at_iso,
                # Отформатированные даты для отображения
                'request_date_display': req.request_date.strftime('%d.%m.%Y') if req.request_date else '-',
                'card_date_display': req.card_date.strftime('%d.%m.%Y') if req.card_date else '-',
                'planned_at_display': (
                    planned_at_local.strftime('%d.%m.%Y') if planned_at_local and planned_at_local.hour == 0 and planned_at_local.minute == 0
                    else planned_at_local.strftime('%d.%m.%Y %H:%M') if planned_at_local
                    else '-'
                ),
                'downlink': float(req.downlink) if req.downlink else None,
                'uplink': float(req.uplink) if req.uplink else None,
                'transfer': float(req.transfer) if req.transfer else None,
                'coords_lat': float(req.coords.y) if req.coords else None,
                'coords_lon': float(req.coords.x) if req.coords else None,
                'region': req.region or '',
                'gso_success': req.gso_success,
                'kubsat_success': req.kubsat_success,
                'coords_source_lat': float(req.coords_source.y) if req.coords_source else None,
                'coords_source_lon': float(req.coords_source.x) if req.coords_source else None,
                'coords_object_lat': float(req.coords_object.y) if req.coords_object else None,
                'coords_object_lon': float(req.coords_object.x) if req.coords_object else None,
                'comment': req.comment or '',
            })
        context['requests_json'] = json.dumps(requests_json_data, ensure_ascii=False)
        
        context['status_choices'] = SourceRequest.STATUS_CHOICES
        context['priority_choices'] = SourceRequest.PRIORITY_CHOICES
        context['current_status'] = status or ''
        context['current_priority'] = priority or ''
        context['search_query'] = self.request.GET.get('search', '')
        
        # Если форма была отправлена, применяем фильтры
        if self.request.GET:
            form = self.form_class(self.request.GET)
            if form.is_valid():
                sources = self.apply_filters(form.cleaned_data)
                date_from = form.cleaned_data.get('date_from')
                date_to = form.cleaned_data.get('date_to')
                has_date_filter = bool(date_from or date_to)
                
                objitem_count_min = form.cleaned_data.get('objitem_count_min')
                objitem_count_max = form.cleaned_data.get('objitem_count_max')
                sources_with_date_info = []
                for source in sources:
                    # Get latest request info for this source
                    latest_request = source.source_requests.order_by('-created_at').first()
                    requests_count = source.source_requests.count()
                    
                    source_data = {
                        'source': source,
                        'objitems_data': [],
                        'has_lyngsat': False,
                        'lyngsat_id': None,
                        'has_request': latest_request is not None,
                        'request_status': latest_request.get_status_display() if latest_request else None,
                        'request_status_raw': latest_request.status if latest_request else None,
                        'gso_success': latest_request.gso_success if latest_request else None,
                        'kubsat_success': latest_request.kubsat_success if latest_request else None,
                        'planned_at': latest_request.planned_at if latest_request else None,
                        'requests_count': requests_count,
                        'average_coords': None,  # Будет рассчитано после сбора точек
                    }
                    
                    for objitem in source.source_objitems.all():
                        # Check if objitem has LyngSat source
                        if hasattr(objitem, 'lyngsat_source') and objitem.lyngsat_source:
                            source_data['has_lyngsat'] = True
                            source_data['lyngsat_id'] = objitem.lyngsat_source.id
                        
                        objitem_matches_date = True
                        objitem_matches_date = True 
                        geo_date = None
                        
                        if hasattr(objitem, 'geo_obj') and objitem.geo_obj and objitem.geo_obj.timestamp:
                            geo_date = objitem.geo_obj.timestamp.date()
                            
                            # Проверяем попадание в диапазон дат (только если фильтр задан)
                            if has_date_filter:
                                if date_from and date_to:
                                    objitem_matches_date = date_from <= geo_date <= date_to
                                elif date_from:
                                    objitem_matches_date = geo_date >= date_from
                                elif date_to:
                                    objitem_matches_date = geo_date <= date_to
                        elif has_date_filter:
                            # Если фильтр по дате задан, но у точки нет даты - не подходит
                            objitem_matches_date = False
                        
                        # Добавляем только точки, подходящие по дате (или все, если фильтр не задан)
                        if not has_date_filter or objitem_matches_date:
                            source_data['objitems_data'].append({
                                'objitem': objitem,
                                'matches_date': objitem_matches_date,
                                'geo_date': geo_date
                            })
                    
                    # ЭТАП 2: Проверяем количество отфильтрованных точек
                    filtered_count = len(source_data['objitems_data'])
                    
                    # Применяем фильтр по количеству точек (если задан)
                    include_source = True
                    if objitem_count_min is not None and filtered_count < objitem_count_min:
                        include_source = False
                    if objitem_count_max is not None and filtered_count > objitem_count_max:
                        include_source = False
                    
                    # Сортируем точки по дате ГЛ перед расчётом усреднённых координат
                    source_data['objitems_data'].sort(
                        key=lambda x: x['geo_date'] if x['geo_date'] else datetime.min.date()
                    )
                    
                    # Рассчитываем усреднённые координаты из отфильтрованных точек
                    if source_data['objitems_data']:
                        avg_coords = None
                        for objitem_info in source_data['objitems_data']:
                            objitem = objitem_info['objitem']
                            if hasattr(objitem, 'geo_obj') and objitem.geo_obj and objitem.geo_obj.coords:
                                coord = (float(objitem.geo_obj.coords.x), float(objitem.geo_obj.coords.y))
                                if avg_coords is None:
                                    avg_coords = coord
                                else:
                                    avg_coords, _ = calculate_mean_coords(avg_coords, coord)
                        if avg_coords:
                            source_data['average_coords'] = avg_coords
                            source_data['avg_lat'] = avg_coords[1]
                            source_data['avg_lon'] = avg_coords[0]
                    
                    if source_data['objitems_data'] and include_source:
                        sources_with_date_info.append(source_data)
                
                context['sources_with_date_info'] = sources_with_date_info
                context['form'] = form
        
        return context
    
    def apply_filters(self, filters):
        """Применяет фильтры к queryset Source"""
        from mainapp.models import SourceRequest
        from django.db.models import Subquery, OuterRef, Exists
        
        queryset = Source.objects.select_related('info', 'ownership').prefetch_related(
            'source_objitems__parameter_obj__id_satellite',
            'source_objitems__parameter_obj__polarization',
            'source_objitems__parameter_obj__modulation',
            'source_objitems__transponder__sat_id',
            'source_objitems__lyngsat_source',
            'source_objitems__geo_obj',
            'source_requests'
        ).annotate(objitem_count=Count('source_objitems'))
        
        # Фильтр по спутникам
        if filters.get('satellites'):
            queryset = queryset.filter(
                source_objitems__parameter_obj__id_satellite__in=filters['satellites']
            ).distinct()
        
        # Фильтр по полосе спутника
        if filters.get('band'):
            queryset = queryset.filter(
                source_objitems__parameter_obj__id_satellite__band__in=filters['band']
            ).distinct()
        
        # Фильтр по поляризации
        if filters.get('polarization'):
            queryset = queryset.filter(
                source_objitems__parameter_obj__polarization__in=filters['polarization']
            ).distinct()
        
        # Фильтр по центральной частоте
        if filters.get('frequency_min'):
            queryset = queryset.filter(
                source_objitems__parameter_obj__frequency__gte=filters['frequency_min']
            )
        if filters.get('frequency_max'):
            queryset = queryset.filter(
                source_objitems__parameter_obj__frequency__lte=filters['frequency_max']
            )
        
        # Фильтр по полосе частот
        if filters.get('freq_range_min'):
            queryset = queryset.filter(
                source_objitems__parameter_obj__freq_range__gte=filters['freq_range_min']
            )
        if filters.get('freq_range_max'):
            queryset = queryset.filter(
                source_objitems__parameter_obj__freq_range__lte=filters['freq_range_max']
            )
        
        # Фильтр по модуляции
        if filters.get('modulation'):
            queryset = queryset.filter(
                source_objitems__parameter_obj__modulation__in=filters['modulation']
            ).distinct()
        
        # Фильтр по типу объекта
        if filters.get('object_type'):
            queryset = queryset.filter(info__in=filters['object_type'])
        
        # Фильтр по принадлежности объекта
        if filters.get('object_ownership'):
            queryset = queryset.filter(ownership__in=filters['object_ownership'])
        
        # Фильтр по количеству ObjItem (диапазон)
        objitem_count_min = filters.get('objitem_count_min')
        objitem_count_max = filters.get('objitem_count_max')
        
        if objitem_count_min is not None:
            queryset = queryset.filter(objitem_count__gte=objitem_count_min)
        if objitem_count_max is not None:
            queryset = queryset.filter(objitem_count__lte=objitem_count_max)
        
        # Фильтр по наличию планов (заявок со статусом 'planned')
        has_plans = filters.get('has_plans')
        if has_plans == 'yes':
            queryset = queryset.filter(
                source_requests__status='planned'
            ).distinct()
        elif has_plans == 'no':
            queryset = queryset.exclude(
                source_requests__status='planned'
            ).distinct()
        
        # Фильтр по ГСО успешно
        success_1 = filters.get('success_1')
        if success_1 == 'yes':
            queryset = queryset.filter(
                source_requests__gso_success=True
            ).distinct()
        elif success_1 == 'no':
            queryset = queryset.filter(
                source_requests__gso_success=False
            ).distinct()
        
        # Фильтр по Кубсат успешно
        success_2 = filters.get('success_2')
        if success_2 == 'yes':
            queryset = queryset.filter(
                source_requests__kubsat_success=True
            ).distinct()
        elif success_2 == 'no':
            queryset = queryset.filter(
                source_requests__kubsat_success=False
            ).distinct()
        
        return queryset.distinct()


class KubsatExportView(LoginRequiredMixin, PermissionRequiredMixin, FormView):
    """Экспорт отфильтрованных данных в Excel"""
    permission_required = 'kubsat_view'
    form_class = KubsatFilterForm
    
    def post(self, request, *args, **kwargs):
        # Получаем список ID точек (ObjItem) из POST
        objitem_ids = request.POST.getlist('objitem_ids')
        
        if not objitem_ids:
            return HttpResponse("Нет данных для экспорта", status=400)
        
        # Получаем ObjItem с их источниками
        objitems = ObjItem.objects.filter(id__in=objitem_ids).select_related(
            'source',
            'source__info',
            'parameter_obj__id_satellite',
            'parameter_obj__polarization',
            'transponder__sat_id',
            'geo_obj'
        ).prefetch_related('geo_obj__mirrors')
        
        # Группируем ObjItem по Source для расчета инкрементального среднего
        sources_objitems = {}
        for objitem in objitems:
            if objitem.source:
                if objitem.source.id not in sources_objitems:
                    sources_objitems[objitem.source.id] = {
                        'source': objitem.source,
                        'objitems': []
                    }
                sources_objitems[objitem.source.id]['objitems'].append(objitem)
        
        # Создаем Excel файл с двумя листами
        wb = Workbook()
        
        # Первый лист: "Предложения" (только основные данные)
        ws_proposals = wb.active
        ws_proposals.title = "Предложения"
        
        # Заголовки для листа "Предложения"
        headers_proposals = [
            'Дата',
            'Широта, град',
            'Долгота, град',
            'Высота, м',
            'Местоположение',
            'ИСЗ',
            'Прямой канал, МГц',
            'Обратный канал, МГц',
            'Перенос'
        ]
        
        # Стиль заголовков для листа "Предложения"
        for col_num, header in enumerate(headers_proposals, 1):
            cell = ws_proposals.cell(row=1, column=col_num, value=header)
            cell.font = Font(bold=True)
            cell.alignment = Alignment(horizontal='center', vertical='center')
        
        # Второй лист: "Комментарий" (все данные)
        ws_comments = wb.create_sheet(title="Комментарий")
        
        # Заголовки для листа "Комментарий"
        headers_comments = [
            'Дата',
            'Широта, град',
            'Долгота, град',
            'Высота, м',
            'Местоположение',
            'ИСЗ',
            'Прямой канал, МГц',
            'Обратный канал, МГц',
            'Перенос',
            'Получено координат, раз',
            'Период получения координат',
            'Зеркала',
            'СКО, км',
            'Примечание',
            'Оператор'
        ]
        
        # Стиль заголовков для листа "Комментарий"
        for col_num, header in enumerate(headers_comments, 1):
            cell = ws_comments.cell(row=1, column=col_num, value=header)
            cell.font = Font(bold=True)
            cell.alignment = Alignment(horizontal='center', vertical='center')
        
        # Заполняем данные
        current_date = datetime.now().strftime('%d.%m.%Y')
        operator_name = f"{request.user.first_name} {request.user.last_name}" if request.user.first_name else request.user.username
        
        row_num_proposals = 2
        row_num_comments = 2
        for source_id, data in sources_objitems.items():
            source = data['source']
            objitems_list = data['objitems']
            
            # Сортируем точки по дате ГЛ перед расчётом
            objitems_list.sort(
                key=lambda x: x.geo_obj.timestamp if x.geo_obj and x.geo_obj.timestamp else datetime.min
            )
            
            # Рассчитываем инкрементальное среднее координат из оставшихся точек
            average_coords = None
            for objitem in objitems_list:
                if hasattr(objitem, 'geo_obj') and objitem.geo_obj and objitem.geo_obj.coords:
                    coord = (objitem.geo_obj.coords.x, objitem.geo_obj.coords.y)
                    
                    if average_coords is None:
                        # Первая точка
                        average_coords = coord
                    else:
                        # Инкрементальное усреднение
                        average_coords, _ = calculate_mean_coords(average_coords, coord)
            
            # Если нет координат из geo_obj, берем из source
            if average_coords is None:
                coords = source.coords_kupsat or source.coords_average or source.coords_valid or source.coords_reference
                if coords:
                    average_coords = (coords.x, coords.y)
            
            latitude = average_coords[1] if average_coords else ''
            longitude = average_coords[0] if average_coords else ''
            
            # Получаем местоположение из первого ObjItem с geo_obj
            location = ''
            for objitem in objitems_list:
                if hasattr(objitem, 'geo_obj') and objitem.geo_obj and objitem.geo_obj.location:
                    location = objitem.geo_obj.location
                    break
            
            # Получаем данные спутника и частоты
            satellite_info = ''
            reverse_channel = ''
            direct_channel = ''
            transfer = ''
            
            for objitem in objitems_list:
                if hasattr(objitem, 'parameter_obj') and objitem.parameter_obj:
                    param = objitem.parameter_obj
                    if param.id_satellite:
                        sat_name = param.id_satellite.name
                        norad = f"({param.id_satellite.norad})" if param.id_satellite.norad else ""
                        satellite_info = f"{sat_name} {norad}"
                    
                    if param.frequency:
                        reverse_channel = param.frequency
                    
                    if objitem.transponder and objitem.transponder.transfer:
                        transfer = objitem.transponder.transfer
                        if param.frequency:
                            direct_channel = param.frequency + objitem.transponder.transfer
                    
                    break
            
            objitem_count = len(objitems_list)
            
            # Зеркала
            mirrors = []
            for objitem in objitems_list:
                if hasattr(objitem, 'geo_obj') and objitem.geo_obj:
                    for mirror in objitem.geo_obj.mirrors.all():
                        if mirror.name not in mirrors:
                            mirrors.append(mirror.name)
            mirrors_str = '\n'.join(mirrors)
            
            # Диапазон дат ГЛ (самая ранняя - самая поздняя)
            geo_dates = []
            for objitem in objitems_list:
                if hasattr(objitem, 'geo_obj') and objitem.geo_obj and objitem.geo_obj.timestamp:
                    geo_dates.append(objitem.geo_obj.timestamp.date())
            
            date_range_str = '-'
            if geo_dates:
                min_date = min(geo_dates)
                max_date = max(geo_dates)
                # Форматируем даты в формате d.m.Y
                min_date_str = min_date.strftime('%d.%m.%Y')
                max_date_str = max_date.strftime('%d.%m.%Y')
                
                if min_date == max_date:
                    # Если даты совпадают, показываем только одну
                    date_range_str = min_date_str
                else:
                    # Иначе показываем диапазон
                    date_range_str = f"{min_date_str}-{max_date_str}"
            
            # Записываем строку на лист "Предложения" (только основные данные)
            ws_proposals.cell(row=row_num_proposals, column=1, value=current_date)
            ws_proposals.cell(row=row_num_proposals, column=2, value=latitude)
            ws_proposals.cell(row=row_num_proposals, column=3, value=longitude)
            ws_proposals.cell(row=row_num_proposals, column=4, value=0.0)
            ws_proposals.cell(row=row_num_proposals, column=5, value=location)
            ws_proposals.cell(row=row_num_proposals, column=6, value=satellite_info)
            ws_proposals.cell(row=row_num_proposals, column=7, value=direct_channel)
            ws_proposals.cell(row=row_num_proposals, column=8, value=reverse_channel)
            ws_proposals.cell(row=row_num_proposals, column=9, value=transfer)
            
            # Записываем строку на лист "Комментарий" (все данные)
            ws_comments.cell(row=row_num_comments, column=1, value=current_date)
            ws_comments.cell(row=row_num_comments, column=2, value=latitude)
            ws_comments.cell(row=row_num_comments, column=3, value=longitude)
            ws_comments.cell(row=row_num_comments, column=4, value=0.0)
            ws_comments.cell(row=row_num_comments, column=5, value=location)
            ws_comments.cell(row=row_num_comments, column=6, value=satellite_info)
            ws_comments.cell(row=row_num_comments, column=7, value=direct_channel)
            ws_comments.cell(row=row_num_comments, column=8, value=reverse_channel)
            ws_comments.cell(row=row_num_comments, column=9, value=transfer)
            ws_comments.cell(row=row_num_comments, column=10, value=objitem_count)
            ws_comments.cell(row=row_num_comments, column=11, value=date_range_str)
            ws_comments.cell(row=row_num_comments, column=12, value=mirrors_str)
            ws_comments.cell(row=row_num_comments, column=13, value='')
            ws_comments.cell(row=row_num_comments, column=14, value='')
            ws_comments.cell(row=row_num_comments, column=15, value=operator_name)
            
            row_num_proposals += 1
            row_num_comments += 1
        
        # Автоширина колонок для обоих листов
        for ws in [ws_proposals, ws_comments]:
            for column in ws.columns:
                max_length = 0
                column_letter = column[0].column_letter
                for cell in column:
                    try:
                        if len(str(cell.value)) > max_length:
                            max_length = len(str(cell.value))
                    except:
                        pass
                adjusted_width = min(max_length + 2, 50)
                ws.column_dimensions[column_letter].width = adjusted_width
        
        # Сохраняем в BytesIO
        output = BytesIO()
        wb.save(output)
        output.seek(0)
        
        # Возвращаем файл
        response = HttpResponse(
            output.read(),
            content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        )
        response['Content-Disposition'] = f'attachment; filename="kubsat_{datetime.now().strftime("%Y%m%d")}.xlsx"'
        
        return response


class KubsatCreateRequestsView(LoginRequiredMixin, PermissionRequiredMixin, FormView):
    """Массовое создание заявок из отфильтрованных данных"""
    permission_required = 'request_create'
    form_class = KubsatFilterForm
    
    def post(self, request, *args, **kwargs):
        import json
        from django.http import JsonResponse
        from mainapp.models import SourceRequest, CustomUser
        
        # Получаем список ID точек (ObjItem) из POST
        objitem_ids = request.POST.getlist('objitem_ids')
        
        if not objitem_ids:
            return JsonResponse({'success': False, 'error': 'Нет данных для создания заявок'}, status=400)
        
        # Получаем ObjItem с их источниками
        objitems = ObjItem.objects.filter(id__in=objitem_ids).select_related(
            'source',
            'geo_obj'
        )
        
        # Группируем ObjItem по Source
        sources_objitems = {}
        for objitem in objitems:
            if objitem.source:
                if objitem.source.id not in sources_objitems:
                    sources_objitems[objitem.source.id] = {
                        'source': objitem.source,
                        'objitems': []
                    }
                sources_objitems[objitem.source.id]['objitems'].append(objitem)
        
        # Получаем CustomUser для текущего пользователя
        try:
            custom_user = CustomUser.objects.get(user=request.user)
        except CustomUser.DoesNotExist:
            custom_user = None
        
        created_count = 0
        errors = []
        
        for source_id, data in sources_objitems.items():
            source = data['source']
            objitems_list = data['objitems']
            
            # Сортируем точки по дате ГЛ перед расчётом
            objitems_list.sort(
                key=lambda x: x.geo_obj.timestamp if x.geo_obj and x.geo_obj.timestamp else datetime.min
            )
            
            # Рассчитываем усреднённые координаты из выбранных точек
            average_coords = None
            points_with_coords = 0
            
            for objitem in objitems_list:
                if hasattr(objitem, 'geo_obj') and objitem.geo_obj and objitem.geo_obj.coords:
                    coord = (objitem.geo_obj.coords.x, objitem.geo_obj.coords.y)
                    points_with_coords += 1
                    
                    if average_coords is None:
                        average_coords = coord
                    else:
                        average_coords, _ = calculate_mean_coords(average_coords, coord)
            
            # Создаём Point объект если есть координаты
            coords_point = None
            if average_coords:
                coords_point = Point(average_coords[0], average_coords[1], srid=4326)
            
            try:
                # Создаём новую заявку со статусом "planned"
                source_request = SourceRequest.objects.create(
                    source=source,
                    status='planned',
                    priority='medium',
                    coords=coords_point,
                    points_count=points_with_coords,
                    created_by=custom_user,
                    updated_by=custom_user,
                    comment=f'Создано из Кубсат. Точек: {len(objitems_list)}'
                )
                created_count += 1
            except Exception as e:
                errors.append(f'Источник #{source_id}: {str(e)}')
        
        return JsonResponse({
            'success': True,
            'created_count': created_count,
            'total_sources': len(sources_objitems),
            'errors': errors
        })


class KubsatRecalculateCoordsView(LoginRequiredMixin, PermissionRequiredMixin, FormView):
    """API для пересчёта усреднённых координат по списку ObjItem ID"""
    permission_required = 'kubsat_view'
    form_class = KubsatFilterForm
    
    def post(self, request, *args, **kwargs):
        import json
        from django.http import JsonResponse
        
        # Получаем список ID точек (ObjItem) из POST
        objitem_ids = request.POST.getlist('objitem_ids')
        
        if not objitem_ids:
            return JsonResponse({'success': False, 'error': 'Нет данных для расчёта'}, status=400)
        
        # Получаем ObjItem с их источниками, сортируем по дате ГЛ
        objitems = ObjItem.objects.filter(id__in=objitem_ids).select_related(
            'source',
            'geo_obj'
        ).order_by('geo_obj__timestamp')  # Сортировка по дате ГЛ
        
        # Группируем ObjItem по Source
        sources_objitems = {}
        for objitem in objitems:
            if objitem.source:
                if objitem.source.id not in sources_objitems:
                    sources_objitems[objitem.source.id] = []
                sources_objitems[objitem.source.id].append(objitem)
        
        # Рассчитываем усреднённые координаты для каждого источника
        results = {}
        for source_id, objitems_list in sources_objitems.items():
            # Сортируем по дате ГЛ (на случай если порядок сбился)
            objitems_list.sort(key=lambda x: x.geo_obj.timestamp if x.geo_obj and x.geo_obj.timestamp else datetime.min)
            
            average_coords = None
            points_count = 0
            
            for objitem in objitems_list:
                if hasattr(objitem, 'geo_obj') and objitem.geo_obj and objitem.geo_obj.coords:
                    coord = (float(objitem.geo_obj.coords.x), float(objitem.geo_obj.coords.y))
                    points_count += 1
                    
                    if average_coords is None:
                        average_coords = coord
                    else:
                        average_coords, _ = calculate_mean_coords(average_coords, coord)
            
            if average_coords:
                results[str(source_id)] = {
                    'avg_lon': average_coords[0],
                    'avg_lat': average_coords[1],
                    'points_count': points_count
                }
            else:
                results[str(source_id)] = {
                    'avg_lon': None,
                    'avg_lat': None,
                    'points_count': 0
                }
        
        return JsonResponse({
            'success': True,
            'results': results
        })
