# Django imports
from django import forms
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import Group, User
from django.shortcuts import redirect
from django.urls import reverse
from django.utils import timezone

# Third-party imports
from import_export.admin import ImportExportActionModelAdmin
from leaflet.admin import LeafletGeoAdmin
from more_admin_filters import (
    MultiSelectDropdownFilter,
    MultiSelectRelatedDropdownFilter,
)
from rangefilter.filters import (
    DateRangeQuickSelectListFilterBuilder,
    NumericRangeFilterBuilder,
)

from .models import (
    Polarization,
    Modulation,
    Standard,
    ObjectMark,
    ObjectInfo,
    ObjectOwnership,
    SigmaParameter,
    Parameter,
    Satellite,
    Geo,
    ObjItem,
    CustomUser,
    UserPermission,
    Band,
    Source,
    TechAnalyze,
    SourceRequest,
    SourceRequestStatusHistory,
)
from .permissions import PERMISSIONS, DEFAULT_ROLE_PERMISSIONS
from .filters import (
    GeoKupDistanceFilter,
    GeoValidDistanceFilter,
    UniqueToggleFilter,
    HasSigmaParameterFilter,
)


admin.site.site_title = "Геолокация"
admin.site.site_header = "Geolocation"
admin.site.index_title = "Geo"

# Unregister default User and Group since we're customizing them
admin.site.unregister(User)
admin.site.unregister(Group)


# ============================================================================
# Base Admin Classes
# ============================================================================


class BaseAdmin(admin.ModelAdmin):
    """
    Базовый класс для всех admin моделей.

    Предоставляет общую функциональность:
    - Кнопки сохранения сверху и снизу
    - Настройка количества элементов на странице
    - Автоматическое заполнение полей created_by и updated_by
    """

    save_on_top = True
    list_per_page = 50

    def save_model(self, request, obj, form, change):
        """
        Автоматически заполняет поля created_by и updated_by при сохранении.

        Args:
            request: HTTP запрос
            obj: Сохраняемый объект модели
            form: Форма с данными
            change: True если это редактирование, False если создание
        """
        if not change:
            # При создании нового объекта устанавливаем created_by
            if hasattr(obj, "created_by") and not obj.created_by_id:
                obj.created_by = getattr(request.user, "customuser", None)

        # При любом сохранении обновляем updated_by
        if hasattr(obj, "updated_by"):
            obj.updated_by = getattr(request.user, "customuser", None)

        super().save_model(request, obj, form, change)


class CustomUserInline(admin.StackedInline):
    model = CustomUser
    can_delete = False
    verbose_name_plural = "Дополнительная информация пользователя"
    filter_horizontal = ('user_permissions',)
    
    fieldsets = (
        (None, {
            'fields': ('role',)
        }),
        ('Индивидуальные разрешения', {
            'fields': ('use_custom_permissions', 'user_permissions'),
            'classes': ('collapse',),
            'description': 'Если включено "Использовать индивидуальные разрешения", '
                          'будут использоваться выбранные разрешения вместо прав роли по умолчанию.'
        }),
    )


class LocationForm(forms.ModelForm):
    latitude_geo = forms.FloatField(required=False, label="Широта")
    longitude_geo = forms.FloatField(required=False, label="Долгота")
    # latitude_kupsat = forms.FloatField(required=False, label="Широта")
    # longitude_kupsat = forms.FloatField(required=False, label="Долгота")
    # latitude_valid = forms.FloatField(required=False, label="Широта")
    # longitude_valid = forms.FloatField(required=False, label="Долгота")

    class Meta:
        model = Geo
        fields = "__all__"

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.instance and self.instance.coords:
            self.fields["latitude_geo"].initial = self.instance.coords[1]
            self.fields["longitude_geo"].initial = self.instance.coords[0]
        # if self.instance and self.instance.coords_kupsat:
        #     self.fields['latitude_kupsat'].initial = self.instance.coords_kupsat[1]
        #     self.fields['longitude_kupsat'].initial = self.instance.coords_kupsat[0]
        # if self.instance and self.instance.coords_valid:
        #     self.fields['latitude_valid'].initial = self.instance.coords_valid[1]
        #     self.fields['longitude_valid'].initial = self.instance.coords_valid[0]

    def save(self, commit=True):
        instance = super().save(commit=False)
        from django.contrib.gis.geos import Point

        lat = self.cleaned_data.get("latitude_geo")
        lon = self.cleaned_data.get("longitude_geo")
        if lat is not None and lon is not None:
            instance.coords = Point(lon, lat, srid=4326)

        # lat = self.cleaned_data.get('latitude_kupsat')
        # lon = self.cleaned_data.get('longitude_kupsat')
        # if lat is not None and lon is not None:
        #     instance.coords_kupsat = Point(lon, lat, srid=4326)

        # lat = self.cleaned_data.get('latitude_valid')
        # lon = self.cleaned_data.get('longitude_valid')
        # if lat is not None and lon is not None:
        #     instance.coords_valid = Point(lon, lat, srid=4326)

        if commit:
            instance.save()
        return instance


class GeoInline(admin.StackedInline):
    model = Geo
    extra = 0
    verbose_name = "Гео"
    verbose_name_plural = "Гео"
    form = LocationForm
    # readonly_fields = ("distance_coords_kup", "distance_coords_valid", "distance_kup_valid")
    prefetch_related = ("mirrors",)
    autocomplete_fields = ("mirrors",)
    fieldsets = (
        (
            "Основная информация",
            {
                "fields": (
                    "mirrors",
                    "location",
                    #    "distance_coords_kup",
                    #     "distance_coords_valid",
                    #     "distance_kup_valid",
                    "timestamp",
                    "comment",
                )
            },
        ),
        (
            "Координаты: геолокация",
            {
                "fields": ("longitude_geo", "latitude_geo", "coords"),
            },
        ),
        # ("Координаты: Кубсат", {
        #     "fields": ("longitude_kupsat", "latitude_kupsat", "coords_kupsat"),
        # }),
        # ("Координаты: Оперативный отдел", {
        #     "fields": ("longitude_valid", "latitude_valid", "coords_valid"),
        # }),
    )


class UserAdmin(BaseUserAdmin):
    inlines = [CustomUserInline]


admin.site.register(User, UserAdmin)


class UserPermissionForm(forms.ModelForm):
    """Форма для UserPermission с выбором из списка разрешений."""
    
    code = forms.ChoiceField(
        choices=[],
        label="Код разрешения",
        help_text="Выберите разрешение из списка"
    )
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['code'].choices = PERMISSIONS[:28]  # Используем PERMISSION_CHOICES
        # Преобразуем в формат (code, name)
        self.fields['code'].choices = [(code, name) for code, name, _ in PERMISSIONS]
    
    class Meta:
        model = UserPermission
        fields = ['code']


@admin.register(UserPermission)
class UserPermissionAdmin(BaseAdmin):
    """Админ-панель для модели UserPermission."""
    
    form = UserPermissionForm
    list_display = ('code', 'get_name', 'get_description')
    search_fields = ('code',)
    ordering = ('code',)
    
    def get_name(self, obj):
        """Возвращает название разрешения."""
        from .permissions import PERMISSION_CHOICES
        choices_dict = dict(PERMISSION_CHOICES)
        return choices_dict.get(obj.code, '-')
    get_name.short_description = 'Название'
    
    def get_description(self, obj):
        """Возвращает описание разрешения."""
        from .permissions import PERMISSION_DESCRIPTIONS
        return PERMISSION_DESCRIPTIONS.get(obj.code, '-')
    get_description.short_description = 'Описание'


@admin.register(CustomUser)
class CustomUserAdmin(BaseAdmin):
    """Админ-панель для модели CustomUser с управлением разрешениями."""
    
    list_display = ('user', 'role', 'use_custom_permissions', 'permissions_count')
    list_filter = ('role', 'use_custom_permissions')
    search_fields = ('user__username', 'user__first_name', 'user__last_name')
    filter_horizontal = ('user_permissions',)
    ordering = ('user__username',)
    
    fieldsets = (
        ('Основная информация', {
            'fields': ('user', 'role')
        }),
        ('Индивидуальные разрешения', {
            'fields': ('use_custom_permissions', 'user_permissions'),
            'description': 'Если включено "Использовать индивидуальные разрешения", '
                          'будут использоваться выбранные разрешения вместо прав роли по умолчанию.'
        }),
    )
    
    def permissions_count(self, obj):
        """Показывает количество индивидуальных разрешений."""
        if obj.use_custom_permissions:
            count = obj.user_permissions.count()
            return f'{count} (индивид.)'
        return f'По роли ({obj.role})'
    permissions_count.short_description = 'Разрешения'
    
    def get_readonly_fields(self, request, obj=None):
        """User поле только для чтения при редактировании."""
        if obj:
            return ('user',)
        return ()
    
    class Media:
        js = ('admin/js/permissions_admin.js',)


# ============================================================================
# Custom Admin Actions
# ============================================================================


@admin.action(description="Показать выбранные на карте")
def show_on_map(modeladmin, request, queryset):
    """
    Action для отображения выбранных Geo объектов на карте.

    Оптимизирован для работы с большим количеством объектов:
    использует values_list для получения только ID.
    """
    selected_ids = queryset.values_list("id", flat=True)
    ids_str = ",".join(str(pk) for pk in selected_ids)
    return redirect(reverse("mainapp:admin_show_map") + f"?ids={ids_str}")


@admin.action(description="Показать выбранные объекты на карте")
def show_selected_on_map(modeladmin, request, queryset):
    """
    Action для отображения выбранных ObjItem объектов на карте.

    Оптимизирован для работы с большим количеством объектов:
    использует values_list для получения только ID.
    """
    selected_ids = queryset.values_list("id", flat=True)
    ids_str = ",".join(str(pk) for pk in selected_ids)
    return redirect(reverse("mainapp:show_selected_objects_map") + f"?ids={ids_str}")


@admin.action(description="Экспортировать выбранные объекты в CSV")
def export_objects_to_csv(modeladmin, request, queryset):
    """
    Action для экспорта выбранных ObjItem объектов в CSV формат.

    Оптимизирован с использованием select_related и prefetch_related
    для минимизации количества запросов к БД.
    """
    import csv
    from django.http import HttpResponse

    # Оптимизируем queryset
    queryset = queryset.select_related(
        "geo_obj",
        "created_by__user",
        "updated_by__user",
        "parameter_obj",
        "parameter_obj__id_satellite",
        "parameter_obj__polarization",
        "parameter_obj__modulation",
    )

    response = HttpResponse(content_type="text/csv; charset=utf-8")
    response["Content-Disposition"] = 'attachment; filename="objitems_export.csv"'
    response.write("\ufeff")  # UTF-8 BOM для корректного отображения в Excel

    writer = csv.writer(response)
    writer.writerow(
        [
            "Название",
            "Спутник",
            "Частота (МГц)",
            "Полоса (МГц)",
            "Поляризация",
            "Модуляция",
            "ОСШ",
            "Координаты геолокации",
            "Координаты Кубсата",
            "Координаты оперативного отдела",
            "Расстояние Гео-Куб (км)",
            "Расстояние Гео-Опер (км)",
            "Дата создания",
            "Дата обновления",
        ]
    )

    for obj in queryset:
        param = getattr(obj, "parameter_obj", None)
        geo = obj.geo_obj

        # Форматирование координат
        def format_coords(coords):
            if not coords:
                return "-"
            lon, lat = coords.coords[0], coords.coords[1]
            lon_str = f"{lon}E" if lon > 0 else f"{abs(lon)}W"
            lat_str = f"{lat}N" if lat > 0 else f"{abs(lat)}S"
            return f"{lat_str} {lon_str}"

        writer.writerow(
            [
                obj.name,
                param.id_satellite.name if param and param.id_satellite else "-",
                param.frequency if param else "-",
                param.freq_range if param else "-",
                param.polarization.name if param and param.polarization else "-",
                param.modulation.name if param and param.modulation else "-",
                param.snr if param else "-",
                format_coords(geo) if geo and geo.coords else "-",
                format_coords(geo) if geo and geo.coords_kupsat else "-",
                format_coords(geo) if geo and geo.coords_valid else "-",
                round(geo.distance_coords_kup, 3)
                if geo and geo.distance_coords_kup
                else "-",
                round(geo.distance_coords_valid, 3)
                if geo and geo.distance_coords_valid
                else "-",
                obj.created_at.strftime("%d.%m.%Y %H:%M:%S") if obj.created_at else "-",
                obj.updated_at.strftime("%d.%m.%Y %H:%M:%S") if obj.updated_at else "-",
            ]
        )

    return response


# ============================================================================
# Inline Admin Classes
# ============================================================================


class ParameterInline(admin.StackedInline):
    """Inline для редактирования параметра объекта."""

    model = Parameter
    extra = 0
    max_num = 1
    can_delete = True
    verbose_name = "ВЧ загрузка"
    verbose_name_plural = "ВЧ загрузка"
    fields = (
        "id_satellite",
        "frequency",
        "freq_range",
        "polarization",
        "modulation",
        "bod_velocity",
        "snr",
        "standard",
    )
    autocomplete_fields = ("id_satellite", "polarization", "modulation", "standard")


# ============================================================================
# Admin Classes
# ============================================================================


@admin.register(ObjectMark)
class ObjectMarkAdmin(BaseAdmin):
    """Админ-панель для модели ObjectMark."""

    list_display = ("id", "tech_analyze", "mark", "timestamp", "created_by")
    list_display_links = ("id",)
    list_select_related = ("tech_analyze", "tech_analyze__satellite", "created_by__user")
    list_editable = ("tech_analyze", "mark", "timestamp")
    search_fields = ("tech_analyze__name", "tech_analyze__id")
    ordering = ("-timestamp",)
    list_filter = (
        "mark",
        ("timestamp", DateRangeQuickSelectListFilterBuilder()),
        ("tech_analyze__satellite", MultiSelectRelatedDropdownFilter),
    )
    autocomplete_fields = ("tech_analyze",)


# @admin.register(SigmaParMark)
# class SigmaParMarkAdmin(BaseAdmin):
#     """Админ-панель для модели SigmaParMark."""

#     list_display = ("mark", "timestamp")
#     search_fields = ("mark",)
#     ordering = ("-timestamp",)
#     list_filter = (("timestamp", DateRangeQuickSelectListFilterBuilder()),)


@admin.register(Polarization)
class PolarizationAdmin(BaseAdmin):
    """Админ-панель для модели Polarization."""

    list_display = ("name",)
    search_fields = ("name",)
    ordering = ("name",)


@admin.register(Modulation)
class ModulationAdmin(BaseAdmin):
    """Админ-панель для модели Modulation."""

    list_display = ("name",)
    search_fields = ("name",)
    ordering = ("name",)


@admin.register(Standard)
class StandardAdmin(BaseAdmin):
    """Админ-панель для модели Standard."""

    list_display = ("name",)
    search_fields = ("name",)
    ordering = ("name",)


@admin.register(ObjectInfo)
class ObjectInfoAdmin(BaseAdmin):
    """Админ-панель для модели ObjectInfo (Тип объекта)."""

    list_display = ("name",)
    search_fields = ("name",)
    ordering = ("name",)


@admin.register(ObjectOwnership)
class ObjectOwnershipAdmin(BaseAdmin):
    """Админ-панель для модели ObjectOwnership (Принадлежность объекта)."""

    list_display = ("name",)
    search_fields = ("name",)
    ordering = ("name",)


class SigmaParameterInline(admin.StackedInline):
    model = SigmaParameter
    extra = 0
    readonly_fields = (
        "datetime_begin",
        "datetime_end",
    )

    def has_add_permission(self, request, obj=None):
        return False


@admin.register(Parameter)
class ParameterAdmin(ImportExportActionModelAdmin, BaseAdmin):
    """
    Админ-панель для модели Parameter.

    Оптимизирована для работы с большим количеством параметров:
    - Использует select_related для оптимизации запросов
    - Предоставляет фильтры по основным характеристикам
    - Поддерживает импорт/экспорт данных
    """

    list_display = (
        "id_satellite",
        "frequency",
        "freq_range",
        "polarization",
        "modulation",
        "bod_velocity",
        "snr",
        "standard",
        "related_objitem",
        "sigma_parameter",
    )
    list_display_links = ("frequency", "id_satellite")
    list_select_related = (
        "polarization",
        "modulation",
        "standard",
        "id_satellite",
        "objitem",
    )

    list_filter = (
        HasSigmaParameterFilter,
        ("objitem", MultiSelectRelatedDropdownFilter),
        ("id_satellite", MultiSelectRelatedDropdownFilter),
        ("polarization__name", MultiSelectDropdownFilter),
        ("modulation", MultiSelectRelatedDropdownFilter),
        ("standard", MultiSelectRelatedDropdownFilter),
        ("frequency", NumericRangeFilterBuilder()),
        ("freq_range", NumericRangeFilterBuilder()),
        ("snr", NumericRangeFilterBuilder()),
    )

    search_fields = (
        "id_satellite__name",
        "frequency",
        "freq_range",
        "bod_velocity",
        "snr",
        "modulation__name",
        "polarization__name",
        "standard__name",
        "objitem__name",
    )

    ordering = ("-frequency",)
    autocomplete_fields = ("objitem",)
    inlines = [SigmaParameterInline]

    def related_objitem(self, obj):
        """Отображает связанный ObjItem."""
        if hasattr(obj, "objitem") and obj.objitem:
            return obj.objitem.name
        return "-"

    related_objitem.short_description = "Объект"
    related_objitem.admin_order_field = "objitem__name"

    def sigma_parameter(self, obj):
        """Отображает связанный параметр Sigma."""
        sigma_obj = obj.sigma_parameter.all()
        if sigma_obj:
            return f"{sigma_obj[0].frequency}: {sigma_obj[0].freq_range}"
        return "-"

    sigma_parameter.short_description = "ВЧ sigma"


@admin.register(SigmaParameter)
class SigmaParameterAdmin(ImportExportActionModelAdmin, BaseAdmin):
    """
    Админ-панель для модели SigmaParameter.

    Оптимизирована для работы с параметрами Sigma:
    - Использует select_related и prefetch_related для оптимизации
    - Предоставляет фильтры по основным характеристикам
    - Поддерживает импорт/экспорт данных
    """

    list_display = (
        "id_satellite",
        "frequency",
        "transfer_frequency",
        "freq_range",
        "polarization",
        "modulation",
        "bod_velocity",
        "snr",
        "parameter",
        "datetime_begin",
        "datetime_end",
    )
    list_display_links = ("id_satellite",)
    list_select_related = (
        "modulation",
        "standard",
        "id_satellite",
        "parameter",
        "polarization",
    )

    readonly_fields = ("datetime_begin", "datetime_end", "transfer_frequency")

    list_filter = (
        ("id_satellite__name", MultiSelectDropdownFilter),
        ("modulation__name", MultiSelectDropdownFilter),
        ("standard__name", MultiSelectDropdownFilter),
        ("frequency", NumericRangeFilterBuilder()),
        ("freq_range", NumericRangeFilterBuilder()),
        ("snr", NumericRangeFilterBuilder()),
        ("datetime_begin", DateRangeQuickSelectListFilterBuilder()),
        ("datetime_end", DateRangeQuickSelectListFilterBuilder()),
    )

    search_fields = (
        "id_satellite__name",
        "frequency",
        "freq_range",
        "bod_velocity",
        "snr",
        "modulation__name",
        "standard__name",
    )
    ordering = ("-frequency",)

    def get_queryset(self, request):
        """Оптимизированный queryset с prefetch_related для mark."""
        qs = super().get_queryset(request)
        return qs.prefetch_related("mark")


@admin.register(Satellite)
class SatelliteAdmin(BaseAdmin):
    """Админ-панель для модели Satellite."""

    list_display = (
        "name",
        "alternative_name",
        "norad",
        "international_code",
        "undersat_point",
        "launch_date",
        "created_at",
        "updated_at",
    )
    search_fields = ("name", "alternative_name", "norad", "international_code")
    ordering = ("name",)
    filter_horizontal = ("band",)
    autocomplete_fields = ("band",)
    readonly_fields = ("created_at", "created_by", "updated_at", "updated_by")


# @admin.register(Mirror)
# class MirrorAdmin(ImportExportActionModelAdmin, BaseAdmin):
#     """Админ-панель для модели Mirror с поддержкой импорта/экспорта."""

#     list_display = ("name",)
#     search_fields = ("name",)
#     ordering = ("name",)


@admin.register(Geo)
class GeoAdmin(ImportExportActionModelAdmin, LeafletGeoAdmin, BaseAdmin):
    """
    Админ-панель для модели Geo с поддержкой карты Leaflet.

    Оптимизирована для работы с геоданными:
    - Использует prefetch_related для оптимизации запросов к mirrors
    - Предоставляет фильтры по зеркалам, локации и дате
    - Поддерживает импорт/экспорт данных
    - Интегрирована с Leaflet для отображения на карте
    """

    form = LocationForm

    # readonly_fields = ("distance_coords_kup", "distance_coords_valid", "distance_kup_valid")

    fieldsets = (
        (
            "Основная информация",
            {
                "fields": (
                    "mirrors",
                    "location",
                    #    "distance_coords_kup",
                    #     "distance_coords_valid",
                    #     "distance_kup_valid",
                    "timestamp",
                    "comment",
                )
            },
        ),
        (
            "Координаты: геолокация",
            {"fields": ("longitude_geo", "latitude_geo", "coords")},
        ),
        # ("Координаты: Кубсат", {
        #     "fields": ("longitude_kupsat", "latitude_kupsat", "coords_kupsat")
        # }),
        # ("Координаты: Оперативный отдел", {
        #     "fields": ("longitude_valid", "latitude_valid", "coords_valid")
        # }),
    )

    list_display = (
        "formatted_timestamp",
        "location",
        "mirrors_names",
        "geo_coords",
        # "kupsat_coords",
        # "valid_coords",
        "is_average",
    )
    list_display_links = ("formatted_timestamp",)

    list_filter = (
        ("mirrors", MultiSelectRelatedDropdownFilter),
        "is_average",
        ("location", MultiSelectDropdownFilter),
        ("timestamp", DateRangeQuickSelectListFilterBuilder()),
    )

    search_fields = (
        "mirrors__name",
        "location",
    )

    autocomplete_fields = ("mirrors",)
    ordering = ("-timestamp",)
    actions = [show_on_map]

    settings_overrides = {
        "DEFAULT_CENTER": (55.7558, 37.6173),
        "DEFAULT_ZOOM": 12,
    }

    def get_queryset(self, request):
        """Оптимизированный queryset с prefetch_related для mirrors."""
        qs = super().get_queryset(request)
        return qs.prefetch_related(
            "mirrors",
        )

    def mirrors_names(self, obj):
        """Отображает список зеркал через запятую."""
        return ", ".join(m.name for m in obj.mirrors.all())

    mirrors_names.short_description = "Зеркала"

    def formatted_timestamp(self, obj):
        """Форматирует timestamp в локальное время."""
        if not obj.timestamp:
            return ""
        local_time = timezone.localtime(obj.timestamp)
        return local_time.strftime("%d.%m.%Y %H:%M:%S")

    formatted_timestamp.short_description = "Дата и время"
    formatted_timestamp.admin_order_field = "timestamp"

    def geo_coords(self, obj):
        """Отображает координаты геолокации в формате широта/долгота."""
        if not obj.coords:
            return "-"
        longitude = obj.coords.coords[0]
        latitude = obj.coords.coords[1]
        lon = f"{longitude}E" if longitude > 0 else f"{abs(longitude)}W"
        lat = f"{latitude}N" if latitude > 0 else f"{abs(latitude)}S"
        return f"{lat} {lon}"

    geo_coords.short_description = "Координаты геолокации"

    # def kupsat_coords(self, obj):
    #     """Отображает координаты Кубсата в формате широта/долгота."""
    #     if obj.coords_kupsat is None:
    #         return "-"
    #     longitude = obj.coords_kupsat.coords[0]
    #     latitude = obj.coords_kupsat.coords[1]
    #     lon = f"{longitude}E" if longitude > 0 else f"{abs(longitude)}W"
    #     lat = f"{latitude}N" if latitude > 0 else f"{abs(latitude)}S"
    #     return f"{lat} {lon}"
    # kupsat_coords.short_description = "Координаты Кубсата"

    # def valid_coords(self, obj):
    #     """Отображает координаты оперативного отдела в формате широта/долгота."""
    #     if obj.coords_valid is None:
    #         return "-"
    #     longitude = obj.coords_valid.coords[0]
    #     latitude = obj.coords_valid.coords[1]
    #     lon = f"{longitude}E" if longitude > 0 else f"{abs(longitude)}W"
    #     lat = f"{latitude}N" if latitude > 0 else f"{abs(latitude)}S"
    #     return f"{lat} {lon}"
    # valid_coords.short_description = "Координаты оперативного отдела"


@admin.register(ObjItem)
class ObjItemAdmin(BaseAdmin):
    """
    Админ-панель для модели ObjItem.

    Оптимизирована для работы с большим количеством объектов:
    - Использует select_related и prefetch_related для оптимизации запросов
    - Предоставляет фильтры по основным параметрам
    - Поддерживает поиск по имени, координатам и частоте
    - Включает кастомные actions для отображения на карте
    """

    list_display = (
        "name",
        "sat_name",
        "freq",
        "freq_range",
        "pol",
        "bod_velocity",
        "modulation",
        "snr",
        "geo_coords",
        # "kupsat_coords",
        # "valid_coords",
        # "distance_geo_kup",
        # "distance_geo_valid",
        # "distance_kup_valid",
        "created_at",
        "updated_at",
    )
    list_display_links = ("name",)
    list_select_related = (
        "geo_obj",
        "created_by__user",
        "updated_by__user",
        "parameter_obj",
        "parameter_obj__id_satellite",
        "parameter_obj__polarization",
        "parameter_obj__modulation",
        "parameter_obj__standard",
    )

    list_filter = (
        UniqueToggleFilter,
        ("parameter_obj__id_satellite", MultiSelectRelatedDropdownFilter),
        ("parameter_obj__frequency", NumericRangeFilterBuilder()),
        ("parameter_obj__freq_range", NumericRangeFilterBuilder()),
        ("parameter_obj__snr", NumericRangeFilterBuilder()),
        ("parameter_obj__modulation", MultiSelectRelatedDropdownFilter),
        ("parameter_obj__polarization", MultiSelectRelatedDropdownFilter),
        GeoKupDistanceFilter,
        GeoValidDistanceFilter,
        ("created_at", DateRangeQuickSelectListFilterBuilder()),
        ("updated_at", DateRangeQuickSelectListFilterBuilder()),
    )

    search_fields = (
        "name",
        "geo_obj__location",
        "parameter_obj__frequency",
        "parameter_obj__id_satellite__name",
    )

    ordering = ("-updated_at",)
    inlines = [GeoInline, ParameterInline]
    actions = [show_selected_on_map, export_objects_to_csv]
    readonly_fields = ("created_at", "created_by", "updated_at", "updated_by")

    fieldsets = (
        ("Основная информация", {"fields": ("name",)}),
        (
            "Метаданные",
            {
                "fields": ("created_at", "created_by", "updated_at", "updated_by"),
                "classes": ("collapse",),
            },
        ),
    )

    def get_queryset(self, request):
        """
        Оптимизированный queryset с использованием select_related.

        Загружает связанные объекты одним запросом для улучшения производительности.
        """
        qs = super().get_queryset(request)
        return qs.select_related(
            "geo_obj",
            "created_by__user",
            "updated_by__user",
            "parameter_obj",
            "parameter_obj__id_satellite",
            "parameter_obj__polarization",
            "parameter_obj__modulation",
            "parameter_obj__standard",
        )

    def sat_name(self, obj):
        """Отображает название спутника из связанного параметра."""
        if hasattr(obj, "parameter_obj") and obj.parameter_obj:
            if obj.parameter_obj.id_satellite:
                return obj.parameter_obj.id_satellite.name
        return "-"

    sat_name.short_description = "Спутник"
    sat_name.admin_order_field = "parameter_obj__id_satellite__name"

    def freq(self, obj):
        """Отображает частоту из связанного параметра."""
        if hasattr(obj, "parameter_obj") and obj.parameter_obj:
            return obj.parameter_obj.frequency
        return "-"

    freq.short_description = "Частота, МГц"
    freq.admin_order_field = "parameter_obj__frequency"

    # def distance_geo_kup(self, obj):
    #     """Отображает расстояние между геолокацией и Кубсатом."""
    #     geo = obj.geo_obj
    #     if not geo or geo.distance_coords_kup is None:
    #         return "-"
    #     return round(geo.distance_coords_kup, 3)
    # distance_geo_kup.short_description = "Гео-куб, км"

    # def distance_geo_valid(self, obj):
    #     """Отображает расстояние между геолокацией и оперативным отделом."""
    #     geo = obj.geo_obj
    #     if not geo or geo.distance_coords_valid is None:
    #         return "-"
    #     return round(geo.distance_coords_valid, 3)
    # distance_geo_valid.short_description = "Гео-опер, км"

    # def distance_kup_valid(self, obj):
    #     """Отображает расстояние между Кубсатом и оперативным отделом."""
    #     geo = obj.geo_obj
    #     if not geo or geo.distance_kup_valid is None:
    #         return "-"
    #     return round(geo.distance_kup_valid, 3)
    # distance_kup_valid.short_description = "Куб-опер, км"

    def pol(self, obj):
        """Отображает поляризацию из связанного параметра."""
        if hasattr(obj, "parameter_obj") and obj.parameter_obj:
            if obj.parameter_obj.polarization:
                return obj.parameter_obj.polarization.name
        return "-"

    pol.short_description = "Поляризация"

    def freq_range(self, obj):
        """Отображает полосу частот из связанного параметра."""
        if hasattr(obj, "parameter_obj") and obj.parameter_obj:
            return obj.parameter_obj.freq_range
        return "-"

    freq_range.short_description = "Полоса, МГц"
    freq_range.admin_order_field = "parameter_obj__freq_range"

    def bod_velocity(self, obj):
        """Отображает символьную скорость из связанного параметра."""
        if hasattr(obj, "parameter_obj") and obj.parameter_obj:
            return obj.parameter_obj.bod_velocity
        return "-"

    bod_velocity.short_description = "Сим. v, БОД"

    def modulation(self, obj):
        """Отображает модуляцию из связанного параметра."""
        if hasattr(obj, "parameter_obj") and obj.parameter_obj:
            if obj.parameter_obj.modulation:
                return obj.parameter_obj.modulation.name
        return "-"

    modulation.short_description = "Модуляция"

    def snr(self, obj):
        """Отображает отношение сигнал/шум из связанного параметра."""
        if hasattr(obj, "parameter_obj") and obj.parameter_obj:
            return obj.parameter_obj.snr
        return "-"

    snr.short_description = "ОСШ"

    def geo_coords(self, obj):
        """Отображает координаты геолокации в формате широта/долгота."""
        geo = obj.geo_obj
        if not geo or not geo.coords:
            return "-"
        longitude = geo.coords.coords[0]
        latitude = geo.coords.coords[1]
        lon = f"{longitude}E" if longitude > 0 else f"{abs(longitude)}W"
        lat = f"{latitude}N" if latitude > 0 else f"{abs(latitude)}S"
        return f"{lat} {lon}"

    geo_coords.short_description = "Координаты геолокации"
    geo_coords.admin_order_field = "geo_obj__coords"

    def kupsat_coords(self, obj):
        """Отображает координаты Кубсата в формате широта/долгота."""
        geo = obj.geo_obj
        if not geo or not geo.coords_kupsat:
            return "-"
        longitude = geo.coords_kupsat.coords[0]
        latitude = geo.coords_kupsat.coords[1]
        lon = f"{longitude}E" if longitude > 0 else f"{abs(longitude)}W"
        lat = f"{latitude}N" if latitude > 0 else f"{abs(latitude)}S"
        return f"{lat} {lon}"

    kupsat_coords.short_description = "Координаты Кубсата"

    def valid_coords(self, obj):
        """Отображает координаты оперативного отдела в формате широта/долгота."""
        geo = obj.geo_obj
        if not geo or not geo.coords_valid:
            return "-"
        longitude = geo.coords_valid.coords[0]
        latitude = geo.coords_valid.coords[1]
        lon = f"{longitude}E" if longitude > 0 else f"{abs(longitude)}W"
        lat = f"{latitude}N" if latitude > 0 else f"{abs(latitude)}S"
        return f"{lat} {lon}"

    valid_coords.short_description = "Координаты оперативного отдела"


@admin.register(Band)
class BandAdmin(ImportExportActionModelAdmin, BaseAdmin):
    """Админ-панель для модели Band."""

    list_display = ("name", "border_start", "border_end")
    search_fields = ("name",)
    ordering = ("name",)


class ObjItemInline(admin.TabularInline):
    """Inline для отображения объектов ObjItem в Source."""

    model = ObjItem
    fk_name = "source"
    extra = 0
    can_delete = False
    verbose_name = "Объект"
    verbose_name_plural = "Объекты"

    fields = (
        "name",
        "get_geo_coords",
        "get_satellite",
        "get_frequency",
        "get_polarization",
        "updated_at",
    )
    readonly_fields = (
        "name",
        "get_geo_coords",
        "get_satellite",
        "get_frequency",
        "get_polarization",
        "updated_at",
    )

    def get_queryset(self, request):
        """Оптимизированный queryset с предзагрузкой связанных объектов."""
        qs = super().get_queryset(request)
        return qs.select_related(
            "geo_obj",
            "parameter_obj",
            "parameter_obj__id_satellite",
            "parameter_obj__polarization",
        )

    def get_geo_coords(self, obj):
        """Отображает координаты из связанной модели Geo."""
        if not obj or not hasattr(obj, "geo_obj"):
            return "-"
        geo = obj.geo_obj
        if not geo or not geo.coords:
            return "-"
        longitude = geo.coords.coords[0]
        latitude = geo.coords.coords[1]
        lon = f"{longitude}E" if longitude > 0 else f"{abs(longitude)}W"
        lat = f"{latitude}N" if latitude > 0 else f"{abs(latitude)}S"
        return f"{lat} {lon}"

    get_geo_coords.short_description = "Координаты"

    def get_satellite(self, obj):
        """Отображает спутник из связанного параметра."""
        if (
            hasattr(obj, "parameter_obj")
            and obj.parameter_obj
            and obj.parameter_obj.id_satellite
        ):
            return obj.parameter_obj.id_satellite.name
        return "-"

    get_satellite.short_description = "Спутник"

    def get_frequency(self, obj):
        """Отображает частоту из связанного параметра."""
        if hasattr(obj, "parameter_obj") and obj.parameter_obj:
            return obj.parameter_obj.frequency
        return "-"

    get_frequency.short_description = "Частота, МГц"

    def get_polarization(self, obj):
        """Отображает поляризацию из связанного параметра."""
        if (
            hasattr(obj, "parameter_obj")
            and obj.parameter_obj
            and obj.parameter_obj.polarization
        ):
            return obj.parameter_obj.polarization.name
        return "-"

    get_polarization.short_description = "Поляризация"

    def has_add_permission(self, request, obj=None):
        return False


@admin.register(Source)
class SourceAdmin(ImportExportActionModelAdmin, LeafletGeoAdmin, BaseAdmin):
    """Админ-панель для модели Source."""

    list_display = ("id", "info", "created_at", "updated_at")
    list_select_related = ("info",)
    list_filter = (
        ("info", MultiSelectRelatedDropdownFilter),
        ("created_at", DateRangeQuickSelectListFilterBuilder()),
        ("updated_at", DateRangeQuickSelectListFilterBuilder()),
    )
    search_fields = ("id", "info__name")
    ordering = ("-created_at",)
    readonly_fields = ("created_at", "created_by", "updated_at", "updated_by")
    inlines = [ObjItemInline]

    fieldsets = (
        (
            "Основная информация",
            {"fields": ("info",)},
        ),
        (
            "Координаты",
            {"fields": ("coords_average", "coords_kupsat", "coords_valid", "coords_reference")},
        ),
        (
            "Метаданные",
            {
                "fields": ("created_at", "created_by", "updated_at", "updated_by"),
                "classes": ("collapse",),
            },
        ),
    )
    
    autocomplete_fields = ("info",)


@admin.register(TechAnalyze)
class TechAnalyzeAdmin(ImportExportActionModelAdmin, BaseAdmin):
    """Админ-панель для модели TechAnalyze."""

    list_display = (
        "name",
        "satellite",
        "frequency",
        "freq_range",
        "polarization",
        "bod_velocity",
        "modulation",
        "standard",
        "created_at",
        "updated_at",
    )
    list_display_links = ("name",)
    list_select_related = (
        "satellite",
        "polarization",
        "modulation",
        "standard",
        "created_by__user",
        "updated_by__user",
    )

    list_filter = (
        ("satellite", MultiSelectRelatedDropdownFilter),
        ("polarization", MultiSelectRelatedDropdownFilter),
        ("modulation", MultiSelectRelatedDropdownFilter),
        ("standard", MultiSelectRelatedDropdownFilter),
        ("frequency", NumericRangeFilterBuilder()),
        ("freq_range", NumericRangeFilterBuilder()),
        ("created_at", DateRangeQuickSelectListFilterBuilder()),
        ("updated_at", DateRangeQuickSelectListFilterBuilder()),
    )

    search_fields = (
        "name",
        "satellite__name",
        "frequency",
        "note",
    )

    ordering = ("-created_at",)
    readonly_fields = ("created_at", "created_by", "updated_at", "updated_by")
    autocomplete_fields = ("satellite", "polarization", "modulation", "standard")

    fieldsets = (
        (
            "Основная информация",
            {"fields": ("name", "satellite", "note")},
        ),
        (
            "Технические параметры",
            {
                "fields": (
                    "frequency",
                    "freq_range",
                    "polarization",
                    "bod_velocity",
                    "modulation",
                    "standard",
                )
            },
        ),
        (
            "Метаданные",
            {
                "fields": ("created_at", "created_by", "updated_at", "updated_by"),
                "classes": ("collapse",),
            },
        ),
    )


class SourceRequestStatusHistoryInline(admin.TabularInline):
    """Inline для отображения истории статусов заявки."""
    model = SourceRequestStatusHistory
    extra = 0
    readonly_fields = ('old_status', 'new_status', 'changed_at', 'changed_by')
    can_delete = False
    
    def has_add_permission(self, request, obj=None):
        return False


@admin.register(SourceRequest)
class SourceRequestAdmin(BaseAdmin):
    """Админ-панель для модели SourceRequest."""
    
    list_display = (
        'id',
        'source',
        'status',
        'priority',
        'planned_at',
        'request_date',
        'gso_success',
        'kubsat_success',
        'points_count',
        'status_updated_at',
        'created_at',
        'created_by',
    )
    list_display_links = ('id', 'source')
    list_select_related = ('source', 'created_by__user', 'updated_by__user')
    
    list_filter = (
        'status',
        'priority',
        'gso_success',
        'kubsat_success',
        ('planned_at', DateRangeQuickSelectListFilterBuilder()),
        ('request_date', DateRangeQuickSelectListFilterBuilder()),
        ('created_at', DateRangeQuickSelectListFilterBuilder()),
    )
    
    search_fields = (
        'source__id',
        'comment',
    )
    
    ordering = ('-created_at',)
    readonly_fields = ('status_updated_at', 'created_at', 'created_by', 'updated_by', 'coords', 'points_count')
    autocomplete_fields = ('source',)
    inlines = [SourceRequestStatusHistoryInline]
    
    fieldsets = (
        (
            'Основная информация',
            {'fields': ('source', 'status', 'priority')},
        ),
        (
            'Даты',
            {'fields': ('planned_at', 'request_date', 'status_updated_at')},
        ),
        (
            'Результаты',
            {'fields': ('gso_success', 'kubsat_success')},
        ),
        (
            'Координаты',
            {'fields': ('coords', 'points_count')},
        ),
        (
            'Комментарий',
            {'fields': ('comment',)},
        ),
        (
            'Метаданные',
            {
                'fields': ('created_at', 'created_by', 'updated_by'),
                'classes': ('collapse',),
            },
        ),
    )


@admin.register(SourceRequestStatusHistory)
class SourceRequestStatusHistoryAdmin(BaseAdmin):
    """Админ-панель для модели SourceRequestStatusHistory."""
    
    list_display = (
        'id',
        'source_request',
        'old_status',
        'new_status',
        'changed_at',
        'changed_by',
    )
    list_display_links = ('id',)
    list_select_related = ('source_request', 'changed_by__user')
    
    list_filter = (
        'old_status',
        'new_status',
        ('changed_at', DateRangeQuickSelectListFilterBuilder()),
    )
    
    search_fields = (
        'source_request__id',
    )
    
    ordering = ('-changed_at',)
    readonly_fields = ('source_request', 'old_status', 'new_status', 'changed_at', 'changed_by')
    
    def has_add_permission(self, request):
        return False
    
    def has_change_permission(self, request, obj=None):
        return False


# ============================================================================
# Errors Report Admin
# ============================================================================

from .models import IssueType, DailyReport, DowntimePeriod, IssueMark


class DowntimePeriodInline(admin.TabularInline):
    """Inline для периодов простоя."""
    model = DowntimePeriod
    extra = 1
    fields = ('start_time', 'end_time', 'reason')


class IssueMarkInline(admin.TabularInline):
    """Inline для отметок об ошибках."""
    model = IssueMark
    extra = 0
    fields = ('issue_type', 'is_present')
    autocomplete_fields = ('issue_type',)


@admin.register(IssueType)
class IssueTypeAdmin(BaseAdmin):
    """Админ-панель для типов ошибок/неисправностей."""
    
    list_display = ('name', 'category')
    list_filter = ('category',)
    search_fields = ('name',)
    ordering = ('category', 'name')


@admin.register(DailyReport)
class DailyReportAdmin(BaseAdmin):
    """Админ-панель для ежедневных отчётов."""
    
    list_display = (
        'date',
        'daily_work_hours',
        'weekly_work_hours',
        'downtime_count',
        'issues_count',
        'created_at',
    )
    list_filter = (
        ('date', DateRangeQuickSelectListFilterBuilder()),
    )
    search_fields = ('explanation', 'comment')
    ordering = ('-date',)
    readonly_fields = ('created_at', 'updated_at', 'created_by')
    inlines = [DowntimePeriodInline, IssueMarkInline]
    
    fieldsets = (
        ('Основная информация', {
            'fields': ('date', 'daily_work_hours', 'weekly_work_hours')
        }),
        ('Примечания', {
            'fields': ('explanation', 'comment')
        }),
        ('Метаданные', {
            'fields': ('created_at', 'updated_at', 'created_by'),
            'classes': ('collapse',)
        }),
    )
    
    def downtime_count(self, obj):
        return obj.downtime_periods.count()
    downtime_count.short_description = 'Простоев'
    
    def issues_count(self, obj):
        return obj.issue_marks.filter(is_present=True).count()
    issues_count.short_description = 'Ошибок/неисправностей'
