"""
Модель источника сигнала (ИРИ).
"""
from django.contrib.gis.db import models as gis
from django.db import models


class Source(models.Model):
    """
    Модель источника сигнала.
    """

    info = models.ForeignKey(
        'mainapp.ObjectInfo',
        on_delete=models.SET_NULL,
        related_name="source_info",
        null=True,
        blank=True,
        verbose_name="Тип объекта",
        help_text="Тип объекта",
    )
    ownership = models.ForeignKey(
        'mainapp.ObjectOwnership',
        on_delete=models.SET_NULL,
        related_name="source_ownership",
        null=True,
        blank=True,
        verbose_name="Принадлежность объекта",
        help_text="Принадлежность объекта (страна, организация и т.д.)",
    )
    note = models.TextField(
        null=True,
        blank=True,
        verbose_name="Примечание",
        help_text="Дополнительное описание объекта",
    )
    confirm_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name="Дата подтверждения",
        help_text="Дата и время добавления последней полученной точки ГЛ",
    )
    last_signal_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name="Последний сигнал",
        help_text="Дата и время последней отметки о наличии сигнала",
    )

    coords_average = gis.PointField(
        srid=4326,
        null=True,
        blank=True,
        verbose_name="Координаты ГЛ",
        help_text="Усреднённые координаты, полученные от в ходе геолокации (WGS84)",
    )
    coords_kupsat = gis.PointField(
        srid=4326,
        null=True,
        blank=True,
        verbose_name="Координаты Кубсата",
        help_text="Координаты, полученные от кубсата (WGS84)",
    )
    coords_valid = gis.PointField(
        srid=4326,
        null=True,
        blank=True,
        verbose_name="Координаты оперативников",
        help_text="Координаты, предоставленные оперативным отделом (WGS84)",
    )
    coords_reference = gis.PointField(
        srid=4326,
        null=True,
        blank=True,
        verbose_name="Координаты справочные",
        help_text="Координаты, ещё кем-то проверенные (WGS84)",
    )

    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name="Дата создания",
        help_text="Дата и время создания записи",
    )
    created_by = models.ForeignKey(
        'mainapp.CustomUser',
        on_delete=models.SET_NULL,
        related_name="source_created",
        null=True,
        blank=True,
        verbose_name="Создан пользователем",
        help_text="Пользователь, создавший запись",
    )
    updated_at = models.DateTimeField(
        auto_now=True,
        verbose_name="Дата последнего изменения",
        help_text="Дата и время последнего изменения",
    )
    updated_by = models.ForeignKey(
        'mainapp.CustomUser',
        on_delete=models.SET_NULL,
        related_name="source_updated",
        null=True,
        blank=True,
        verbose_name="Изменен пользователем",
        help_text="Пользователь, последним изменивший запись",
    )

    def update_coords_average(self, new_coord_tuple):
        """
        Обновляет coords_average в зависимости от типа объекта (info).
        
        Логика:
        - Если info == "Подвижные": coords_average = последняя добавленная координата
        - Иначе (Стационарные и др.): coords_average = инкрементальное среднее
        
        Args:
            new_coord_tuple: кортеж (longitude, latitude) новой координаты
        """
        from django.contrib.gis.geos import Point
        from ..utils import calculate_mean_coords
        
        # Если тип объекта "Подвижные" - просто устанавливаем последнюю координату
        if self.info and self.info.name == "Подвижные":
            self.coords_average = Point(new_coord_tuple, srid=4326)
        else:
            # Для стационарных объектов - вычисляем среднее
            if self.coords_average:
                # Есть предыдущее среднее - вычисляем новое среднее
                current_coord = (self.coords_average.x, self.coords_average.y)
                new_avg, _ = calculate_mean_coords(current_coord, new_coord_tuple)
                self.coords_average = Point(new_avg, srid=4326)
            else:
                # Первая координата - просто устанавливаем её
                self.coords_average = Point(new_coord_tuple, srid=4326)

    def get_last_geo_coords(self):
        """
        Получает координаты последней добавленной точки ГЛ для этого источника.
        Сортировка по ID (последняя добавленная в базу).
        
        Returns:
            tuple: (longitude, latitude) или None если точек нет
        """
        # Получаем последний ObjItem для этого Source (по ID)
        last_objitem = self.source_objitems.filter(
            geo_obj__coords__isnull=False
        ).select_related('geo_obj').order_by('-id').first()
        
        if last_objitem and last_objitem.geo_obj and last_objitem.geo_obj.coords:
            return (last_objitem.geo_obj.coords.x, last_objitem.geo_obj.coords.y)
        
        return None

    def update_confirm_at(self):
        """
        Обновляет дату confirm_at на дату создания последней добавленной точки ГЛ.
        """
        last_objitem = self.source_objitems.order_by('-created_at').first()
        if last_objitem:
            self.confirm_at = last_objitem.created_at

    def save(self, *args, **kwargs):
        """
        Переопределенный метод save для автоматического обновления coords_average
        при изменении типа объекта.
        """
        from django.contrib.gis.geos import Point
        
        # Проверяем, изменился ли тип объекта
        if self.pk:  # Объект уже существует
            try:
                old_instance = Source.objects.get(pk=self.pk)
                old_info = old_instance.info
                new_info = self.info
                
                # Если тип изменился на "Подвижные"
                if new_info and new_info.name == "Подвижные" and (not old_info or old_info.name != "Подвижные"):
                    # Устанавливаем координату последней точки
                    last_coords = self.get_last_geo_coords()
                    if last_coords:
                        self.coords_average = Point(last_coords, srid=4326)
                
                # Если тип изменился с "Подвижные" на что-то другое
                elif old_info and old_info.name == "Подвижные" and (not new_info or new_info.name != "Подвижные"):
                    # Пересчитываем среднюю координату по всем точкам
                    self._recalculate_average_coords()
                    
            except Source.DoesNotExist:
                pass
        
        super().save(*args, **kwargs)

    def _recalculate_average_coords(self):
        """
        Пересчитывает среднюю координату по всем точкам источника.
        Используется при переключении с "Подвижные" на "Стационарные".
        
        Сортировка по ID (порядок добавления в базу), инкрементальное усреднение
        как в функциях импорта.
        """
        from django.contrib.gis.geos import Point
        from ..utils import calculate_mean_coords
        
        # Получаем все точки для этого источника, сортируем по ID (порядок добавления)
        objitems = self.source_objitems.filter(
            geo_obj__coords__isnull=False
        ).select_related('geo_obj').order_by('id')
        
        if not objitems.exists():
            return
        
        # Вычисляем среднюю координату инкрементально (как в функциях импорта)
        coords_average = None
        for objitem in objitems:
            if objitem.geo_obj and objitem.geo_obj.coords:
                coord = (objitem.geo_obj.coords.x, objitem.geo_obj.coords.y)
                if coords_average is None:
                    # Первая точка - просто устанавливаем её
                    coords_average = coord
                else:
                    # Последующие точки - вычисляем среднее между текущим средним и новой точкой
                    coords_average, _ = calculate_mean_coords(coords_average, coord)
        
        if coords_average:
            self.coords_average = Point(coords_average, srid=4326)

    class Meta:
        verbose_name = "Источник"
        verbose_name_plural = "Источники"
