# Django imports
from django import forms

# Local imports
from .models import (
    Geo,
    Modulation,
    ObjItem,
    Parameter,
    Polarization,
    Satellite,
    Source,
    Standard,
)
from .widgets import CheckboxSelectMultipleWidget

# Import from mapsapp to avoid circular import issues
from mapsapp.models import Transponders


class UploadFileForm(forms.Form):
    file = forms.FileField(
        label="Выберите файл",
        widget=forms.FileInput(attrs={"class": "form-file-input"}),
    )


class LoadExcelData(forms.Form):
    file = forms.FileField(
        label="Выберите Excel файл",
        widget=forms.FileInput(attrs={"class": "form-control", "accept": ".xlsx,.xls"}),
    )
    sat_choice = forms.ModelChoiceField(
        queryset=Satellite.objects.all(),
        label="Выберите спутник",
        widget=forms.Select(attrs={"class": "form-select"}),
    )
    number_input = forms.IntegerField(
        label="Введите число объектов",
        min_value=0,
        widget=forms.NumberInput(attrs={"class": "form-control"}),
    )
    is_automatic = forms.BooleanField(
        label="Автоматическая загрузка",
        required=False,
        initial=False,
        widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
        help_text="Если отмечено, точки не будут добавляться к объектам",
    )


class LoadCsvData(forms.Form):
    file = forms.FileField(
        label="Выберите CSV файл",
        widget=forms.FileInput(attrs={"class": "form-control", "accept": ".csv"}),
    )
    is_automatic = forms.BooleanField(
        label="Автоматическая загрузка",
        required=False,
        initial=False,
        widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
        help_text="Если отмечено, точки не будут добавляться к объектам",
    )


class UploadVchLoad(UploadFileForm):
    sat_choice = forms.ModelChoiceField(
        queryset=Satellite.objects.all(),
        label="Выберите спутник",
        widget=forms.Select(attrs={"class": "form-select"}),
    )


class VchLinkForm(forms.Form):
    sat_choice = forms.ModelChoiceField(
        queryset=Satellite.objects.all(),
        label="Выберите спутник",
        widget=forms.Select(attrs={"class": "form-select"}),
    )
    # ku_range = forms.ChoiceField(
    #     choices=[(9750.0, '9750'), (10750.0, '10750')],
    #     # coerce=lambda x: x == 'True',
    #     widget=forms.Select(attrs={'class': 'form-select'}),
    #     label='Выбор диапазона'
    # )
    value1 = forms.FloatField(
        label="Разброс по частоте (не используется)",
        required=False,
        initial=0.0,
        widget=forms.NumberInput(
            attrs={
                "class": "form-control",
                "placeholder": "Не используется - погрешность определяется автоматически",
            }
        ),
    )
    value2 = forms.FloatField(
        label="Разброс по полосе (в %)",
        widget=forms.NumberInput(
            attrs={
                "class": "form-control",
                "placeholder": "Введите погрешность полосы в процентах",
                "step": "0.1",
            }
        ),
    )


class NewEventForm(forms.Form):
    # sat_choice = forms.ModelChoiceField(
    #     queryset=Satellite.objects.all(),
    #     label="Выберите спутник",
    #     widget=forms.Select(attrs={
    #         'class': 'form-select'
    #     })
    # )
    # pol_choice = forms.ModelChoiceField(
    #     queryset=Polarization.objects.all(),
    #     label="Выберите поляризацию",
    #     widget=forms.Select(attrs={
    #         'class': 'form-select'
    #     })
    # )
    file = forms.FileField(
        label="Выберите файл",
        widget=forms.FileInput(attrs={"class": "form-control", "accept": ".xlsx,.xls"}),
    )


class FillLyngsatDataForm(forms.Form):
    """Форма для заполнения данных из Lyngsat с поддержкой кеширования"""

    REGION_CHOICES = [
        ("europe", "Европа"),
        ("asia", "Азия"),
        ("america", "Америка"),
        ("atlantic", "Атлантика"),
    ]

    satellites = forms.ModelMultipleChoiceField(
        queryset=Satellite.objects.all().order_by("name"),
        label="Выберите спутники",
        widget=forms.SelectMultiple(attrs={"class": "form-select", "size": "10"}),
        required=True,
        help_text="Удерживайте Ctrl (Cmd на Mac) для выбора нескольких спутников",
    )

    regions = forms.MultipleChoiceField(
        choices=REGION_CHOICES,
        label="Выберите регионы",
        widget=forms.SelectMultiple(attrs={"class": "form-select", "size": "4"}),
        required=True,
        initial=["europe", "asia", "america", "atlantic"],
        help_text="Удерживайте Ctrl (Cmd на Mac) для выбора нескольких регионов",
    )

    use_cache = forms.BooleanField(
        label="Использовать кеширование",
        required=False,
        initial=True,
        widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
        help_text="Использовать кешированные данные (ускоряет повторные запросы)",
    )

    force_refresh = forms.BooleanField(
        label="Принудительно обновить данные",
        required=False,
        initial=False,
        widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
        help_text="Игнорировать кеш и получить свежие данные с сайта",
    )


class LinkLyngsatForm(forms.Form):
    """Форма для привязки источников LyngSat к объектам"""

    satellites = forms.ModelMultipleChoiceField(
        queryset=Satellite.objects.all().order_by("name"),
        label="Выберите спутники",
        widget=forms.SelectMultiple(attrs={"class": "form-select", "size": "10"}),
        required=False,
        help_text="Оставьте пустым для обработки всех спутников",
    )

    frequency_tolerance = forms.FloatField(
        label="Допуск по частоте (МГц)",
        initial=0.5,
        min_value=0,
        widget=forms.NumberInput(attrs={"class": "form-control", "step": "0.1"}),
        help_text="Допустимое отклонение частоты при сравнении",
    )


class ParameterForm(forms.ModelForm):
    """
    Форма для создания и редактирования параметров ВЧ загрузки.

    Работает с одним экземпляром Parameter, связанным с ObjItem через OneToOne связь.
    """

    class Meta:
        model = Parameter
        fields = [
            "id_satellite",
            "frequency",
            "freq_range",
            "polarization",
            "bod_velocity",
            "modulation",
            "snr",
            "standard",
        ]
        widgets = {
            "id_satellite": forms.Select(
                attrs={"class": "form-select", "required": True}
            ),
            "frequency": forms.NumberInput(
                attrs={
                    "class": "form-control",
                    "step": "0.000001",
                    "min": "0",
                    "max": "50000",
                    "placeholder": "Введите частоту в МГц",
                }
            ),
            "freq_range": forms.NumberInput(
                attrs={
                    "class": "form-control",
                    "step": "0.000001",
                    "min": "0",
                    "max": "1000",
                    "placeholder": "Введите полосу частот в МГц",
                }
            ),
            "bod_velocity": forms.NumberInput(
                attrs={
                    "class": "form-control",
                    "step": "0.001",
                    "min": "0",
                    "placeholder": "Введите символьную скорость в БОД",
                }
            ),
            "snr": forms.NumberInput(
                attrs={
                    "class": "form-control",
                    "step": "0.001",
                    "min": "-50",
                    "max": "100",
                    "placeholder": "Введите ОСШ в дБ",
                }
            ),
            "polarization": forms.Select(attrs={"class": "form-select"}),
            "modulation": forms.Select(attrs={"class": "form-select"}),
            "standard": forms.Select(attrs={"class": "form-select"}),
        }
        labels = {
            "id_satellite": "Спутник",
            "frequency": "Частота (МГц)",
            "freq_range": "Полоса частот (МГц)",
            "polarization": "Поляризация",
            "bod_velocity": "Символьная скорость (БОД)",
            "modulation": "Модуляция",
            "snr": "ОСШ (дБ)",
            "standard": "Стандарт",
        }
        help_texts = {
            "frequency": "Частота в диапазоне от 0 до 50000 МГц",
            "freq_range": "Полоса частот в диапазоне от 0 до 1000 МГц",
            "bod_velocity": "Символьная скорость должна быть положительной",
            "snr": "Отношение сигнал/шум в диапазоне от -50 до 100 дБ",
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Динамически загружаем choices для select полей
        self.fields["id_satellite"].queryset = Satellite.objects.all().order_by("name")
        self.fields["polarization"].queryset = Polarization.objects.all().order_by(
            "name"
        )
        self.fields["modulation"].queryset = Modulation.objects.all().order_by("name")
        self.fields["standard"].queryset = Standard.objects.all().order_by("name")

        # Делаем спутник обязательным полем
        self.fields["id_satellite"].required = True

    def clean(self):
        """
        Дополнительная валидация формы.

        Проверяет соотношение между частотой, полосой частот и символьной скоростью.
        """
        cleaned_data = super().clean()
        frequency = cleaned_data.get("frequency")
        freq_range = cleaned_data.get("freq_range")
        bod_velocity = cleaned_data.get("bod_velocity")

        # Проверка что частота больше полосы частот
        if frequency and freq_range:
            if freq_range > frequency:
                self.add_error(
                    "freq_range", "Полоса частот не может быть больше частоты"
                )

        # Проверка что символьная скорость соответствует полосе частот
        if bod_velocity and freq_range:
            if bod_velocity > freq_range * 1000000:  # Конвертация МГц в Гц
                self.add_error(
                    "bod_velocity",
                    "Символьная скорость не может превышать полосу частот",
                )

        return cleaned_data


class GeoForm(forms.ModelForm):
    class Meta:
        model = Geo
        fields = ["location", "comment", "is_average", "mirrors"]
        widgets = {
            "location": forms.TextInput(attrs={"class": "form-control"}),
            "comment": forms.TextInput(attrs={"class": "form-control"}),
            "is_average": forms.CheckboxInput(attrs={"class": "form-check-input"}),
            "mirrors": CheckboxSelectMultipleWidget(
                attrs={
                    "id": "id_geo-mirrors",
                    "placeholder": "Выберите спутники...",
                }
            ),
        }
        labels = {
            "location": "Местоположение",
            "comment": "Комментарий",
            "is_average": "Усреднённое",
            "mirrors": "Спутники-зеркала, использованные для приёма",
        }
        help_texts = {
            "mirrors": "Выберите спутники из списка",
        }


class ObjItemForm(forms.ModelForm):
    """
    Форма для создания и редактирования объектов (источников сигнала).

    Работает с моделью ObjItem. Параметры ВЧ загрузки обрабатываются отдельно
    через ParameterForm с использованием OneToOne связи.
    """

    class Meta:
        model = ObjItem
        fields = ["name"]
        widgets = {
            "name": forms.TextInput(
                attrs={
                    "class": "form-control",
                    "placeholder": "Введите название объекта",
                    "maxlength": "100",
                }
            ),
        }
        labels = {
            "name": "Название объекта",
        }
        help_texts = {
            "name": "Уникальное название объекта/источника сигнала",
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Делаем поле name необязательным, так как оно может быть пустым
        self.fields["name"].required = False

    def clean_name(self):
        """
        Валидация поля name.

        Проверяет что название не состоит только из пробелов.
        """
        name = self.cleaned_data.get("name")

        if name:
            # Удаляем лишние пробелы
            name = name.strip()

            # Проверяем что после удаления пробелов что-то осталось
            if not name:
                raise forms.ValidationError(
                    "Название не может состоять только из пробелов"
                )

        return name


class SourceForm(forms.ModelForm):
    """Form for editing Source model with 4 coordinate fields."""

    # Координаты ГЛ (coords_average)
    average_latitude = forms.FloatField(
        required=False,
        widget=forms.NumberInput(
            attrs={"class": "form-control", "step": "0.000001", "placeholder": "Широта"}
        ),
        label="Широта ГЛ",
    )
    average_longitude = forms.FloatField(
        required=False,
        widget=forms.NumberInput(
            attrs={
                "class": "form-control",
                "step": "0.000001",
                "placeholder": "Долгота",
            }
        ),
        label="Долгота ГЛ",
    )

    # Координаты Кубсата (coords_kupsat)
    kupsat_latitude = forms.FloatField(
        required=False,
        widget=forms.NumberInput(
            attrs={"class": "form-control", "step": "0.000001", "placeholder": "Широта"}
        ),
        label="Широта Кубсата",
    )
    kupsat_longitude = forms.FloatField(
        required=False,
        widget=forms.NumberInput(
            attrs={
                "class": "form-control",
                "step": "0.000001",
                "placeholder": "Долгота",
            }
        ),
        label="Долгота Кубсата",
    )

    # Координаты оперативников (coords_valid)
    valid_latitude = forms.FloatField(
        required=False,
        widget=forms.NumberInput(
            attrs={"class": "form-control", "step": "0.000001", "placeholder": "Широта"}
        ),
        label="Широта оперативников",
    )
    valid_longitude = forms.FloatField(
        required=False,
        widget=forms.NumberInput(
            attrs={
                "class": "form-control",
                "step": "0.000001",
                "placeholder": "Долгота",
            }
        ),
        label="Долгота оперативников",
    )

    # Координаты справочные (coords_reference)
    reference_latitude = forms.FloatField(
        required=False,
        widget=forms.NumberInput(
            attrs={"class": "form-control", "step": "0.000001", "placeholder": "Широта"}
        ),
        label="Широта справочные",
    )
    reference_longitude = forms.FloatField(
        required=False,
        widget=forms.NumberInput(
            attrs={
                "class": "form-control",
                "step": "0.000001",
                "placeholder": "Долгота",
            }
        ),
        label="Долгота справочные",
    )

    class Meta:
        model = Source
        fields = ['info', 'ownership', 'note']
        widgets = {
            'info': forms.Select(attrs={
                'class': 'form-select',
                'id': 'id_info',
            }),
            'ownership': forms.Select(attrs={
                'class': 'form-select',
                'id': 'id_ownership',
            }),
            'note': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': "3",
                'id': 'id_note',
            })
        }
        labels = {
            'info': 'Тип объекта',
            'ownership': 'Принадлежность объекта',
            'note': 'Примечание'
        }
        help_texts = {
            'info': 'Стационарные: координата усредняется. Подвижные: координата = последняя точка. При изменении типа координата пересчитывается автоматически.',
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Заполняем поля координат из instance
        if self.instance and self.instance.pk:
            if self.instance.coords_average:
                self.fields[
                    "average_longitude"
                ].initial = self.instance.coords_average.x
                self.fields["average_latitude"].initial = self.instance.coords_average.y

            if self.instance.coords_kupsat:
                self.fields["kupsat_longitude"].initial = self.instance.coords_kupsat.x
                self.fields["kupsat_latitude"].initial = self.instance.coords_kupsat.y

            if self.instance.coords_valid:
                self.fields["valid_longitude"].initial = self.instance.coords_valid.x
                self.fields["valid_latitude"].initial = self.instance.coords_valid.y

            if self.instance.coords_reference:
                self.fields[
                    "reference_longitude"
                ].initial = self.instance.coords_reference.x
                self.fields[
                    "reference_latitude"
                ].initial = self.instance.coords_reference.y

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

        instance = super().save(commit=False)

        # coords_average НЕ обрабатываем здесь - это поле управляется только программно
        # (через _recalculate_average_coords в модели Source)

        # Обработка coords_kupsat
        kup_lat = self.cleaned_data.get("kupsat_latitude")
        kup_lng = self.cleaned_data.get("kupsat_longitude")
        if kup_lat is not None and kup_lng is not None:
            instance.coords_kupsat = Point(kup_lng, kup_lat, srid=4326)
        else:
            instance.coords_kupsat = None

        # Обработка coords_valid
        val_lat = self.cleaned_data.get("valid_latitude")
        val_lng = self.cleaned_data.get("valid_longitude")
        if val_lat is not None and val_lng is not None:
            instance.coords_valid = Point(val_lng, val_lat, srid=4326)
        else:
            instance.coords_valid = None

        # Обработка coords_reference
        ref_lat = self.cleaned_data.get("reference_latitude")
        ref_lng = self.cleaned_data.get("reference_longitude")
        if ref_lat is not None and ref_lng is not None:
            instance.coords_reference = Point(ref_lng, ref_lat, srid=4326)
        else:
            instance.coords_reference = None

        if commit:
            instance.save()

        return instance



class KubsatFilterForm(forms.Form):
    """Форма фильтров для страницы Кубсат"""
    
    satellites = forms.ModelMultipleChoiceField(
        queryset=None,  # Будет установлен в __init__
        label='Спутники',
        required=False,
        widget=forms.SelectMultiple(attrs={'class': 'form-select', 'size': '5'})
    )
    
    band = forms.ModelMultipleChoiceField(
        queryset=None,
        label='Диапазоны работы спутника',
        required=False,
        widget=forms.SelectMultiple(attrs={'class': 'form-select', 'size': '5'})
    )
    
    polarization = forms.ModelMultipleChoiceField(
        queryset=Polarization.objects.all().order_by('name'),
        label='Поляризация',
        required=False,
        widget=forms.SelectMultiple(attrs={'class': 'form-select', 'size': '5'})
    )
    
    frequency_min = forms.FloatField(
        label='Центральная частота от (МГц)',
        required=False,
        widget=forms.NumberInput(attrs={'class': 'form-control', 'step': '0.001'})
    )
    
    frequency_max = forms.FloatField(
        label='Центральная частота до (МГц)',
        required=False,
        widget=forms.NumberInput(attrs={'class': 'form-control', 'step': '0.001'})
    )
    
    freq_range_min = forms.FloatField(
        label='Полоса от (МГц)',
        required=False,
        widget=forms.NumberInput(attrs={'class': 'form-control', 'step': '0.001'})
    )
    
    freq_range_max = forms.FloatField(
        label='Полоса до (МГц)',
        required=False,
        widget=forms.NumberInput(attrs={'class': 'form-control', 'step': '0.001'})
    )
    
    modulation = forms.ModelMultipleChoiceField(
        queryset=Modulation.objects.all().order_by('name'),
        label='Модуляция',
        required=False,
        widget=forms.SelectMultiple(attrs={'class': 'form-select', 'size': '5'})
    )
    
    object_type = forms.ModelMultipleChoiceField(
        queryset=None,
        label='Тип объекта',
        required=False,
        widget=forms.SelectMultiple(attrs={'class': 'form-select', 'size': '3'})
    )
    
    object_ownership = forms.ModelMultipleChoiceField(
        queryset=None,
        label='Принадлежность объекта',
        required=False,
        widget=forms.SelectMultiple(attrs={'class': 'form-select', 'size': '3'})
    )
    
    objitem_count_min = forms.IntegerField(
        label='Количество привязанных точек ГЛ от',
        required=False,
        min_value=0,
        widget=forms.NumberInput(attrs={'class': 'form-control', 'placeholder': 'От'})
    )
    
    objitem_count_max = forms.IntegerField(
        label='Количество привязанных точек ГЛ до',
        required=False,
        min_value=0,
        widget=forms.NumberInput(attrs={'class': 'form-control', 'placeholder': 'До'})
    )
    
    # Фиктивные фильтры
    has_plans = forms.ChoiceField(
        choices=[('', 'Неважно'), ('yes', 'Да'), ('no', 'Нет')],
        label='Планы на Кубсат',
        required=False,
        widget=forms.RadioSelect()
    )
    
    success_1 = forms.ChoiceField(
        choices=[('', 'Неважно'), ('yes', 'Да'), ('no', 'Нет')],
        label='ГСО успешно?',
        required=False,
        widget=forms.RadioSelect()
    )
    
    success_2 = forms.ChoiceField(
        choices=[('', 'Неважно'), ('yes', 'Да'), ('no', 'Нет')],
        label='Кубсат успешно?',
        required=False,
        widget=forms.RadioSelect()
    )
    
    date_from = forms.DateField(
        label='Дата от',
        required=False,
        widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'})
    )
    
    date_to = forms.DateField(
        label='Дата до',
        required=False,
        widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'})
    )
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        from mainapp.models import Band, ObjectInfo, ObjectOwnership, Satellite, ObjItem
        from django.db.models import Exists, OuterRef
        
        # Фильтруем спутники: только те, у которых есть источники с точками
        satellites_with_sources = Satellite.objects.filter(
            parameters__objitem__source__isnull=False
        ).distinct().order_by('name')
        
        self.fields['satellites'].queryset = satellites_with_sources
        self.fields['band'].queryset = Band.objects.all().order_by('name')
        self.fields['object_type'].queryset = ObjectInfo.objects.all().order_by('name')
        self.fields['object_ownership'].queryset = ObjectOwnership.objects.all().order_by('name')


class TransponderForm(forms.ModelForm):
    """
    Форма для создания и редактирования транспондеров.
    
    При редактировании только name, zone_name и snr доступны для изменения.
    Остальные поля только для чтения.
    """
    
    class Meta:
        model = Transponders
        fields = [
            'name',
            'sat_id',
            'downlink',
            'uplink',
            'frequency_range',
            'zone_name',
            'polarization',
            'snr',
        ]
        widgets = {
            'name': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': 'Введите название транспондера'
            }),
            'sat_id': forms.Select(attrs={'class': 'form-select'}),
            'downlink': forms.NumberInput(attrs={
                'class': 'form-control',
                'step': '0.001',
                'placeholder': 'Введите частоту downlink в МГц'
            }),
            'uplink': forms.NumberInput(attrs={
                'class': 'form-control',
                'step': '0.001',
                'placeholder': 'Введите частоту uplink в МГц'
            }),
            'frequency_range': forms.NumberInput(attrs={
                'class': 'form-control',
                'step': '0.001',
                'placeholder': 'Введите полосу частот в МГц'
            }),
            'zone_name': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': 'Введите название зоны покрытия'
            }),
            'polarization': forms.Select(attrs={'class': 'form-select'}),
            'snr': forms.NumberInput(attrs={
                'class': 'form-control',
                'step': '0.1',
                'placeholder': 'Введите ОСШ в дБ'
            }),
        }
        labels = {
            'name': 'Название транспондера',
            'sat_id': 'Спутник',
            'downlink': 'Downlink (МГц)',
            'uplink': 'Uplink (МГц)',
            'frequency_range': 'Полоса частот (МГц)',
            'zone_name': 'Название зоны покрытия',
            'polarization': 'Поляризация',
            'snr': 'ОСШ (дБ)',
        }
        help_texts = {
            'downlink': 'Частота downlink в МГц',
            'uplink': 'Частота uplink в МГц',
            'frequency_range': 'Полоса частот в МГц',
            'snr': 'Отношение сигнал/шум в децибелах',
        }
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        # Загружаем choices для select полей
        self.fields['sat_id'].queryset = Satellite.objects.all().order_by('name')
        self.fields['polarization'].queryset = Polarization.objects.all().order_by('name')
        
        # Если это форма редактирования (instance существует), делаем поля readonly
        if self.instance and self.instance.pk:
            # Поля только для чтения при редактировании
            readonly_fields = ['sat_id', 'downlink', 'uplink', 'frequency_range', 'polarization']
            for field_name in readonly_fields:
                self.fields[field_name].widget.attrs['readonly'] = True
                self.fields[field_name].widget.attrs['disabled'] = True
                self.fields[field_name].required = False
        else:
            # При создании все поля обязательны кроме name, zone_name и snr
            self.fields['sat_id'].required = True
            self.fields['downlink'].required = True
            self.fields['name'].required = False
            self.fields['zone_name'].required = False
            self.fields['snr'].required = False
    
    def clean(self):
        """Дополнительная валидация формы."""
        cleaned_data = super().clean()
        
        # При редактировании восстанавливаем значения readonly полей из instance
        if self.instance and self.instance.pk:
            cleaned_data['sat_id'] = self.instance.sat_id
            cleaned_data['downlink'] = self.instance.downlink
            cleaned_data['uplink'] = self.instance.uplink
            cleaned_data['frequency_range'] = self.instance.frequency_range
            cleaned_data['polarization'] = self.instance.polarization
        
        return cleaned_data


class SatelliteForm(forms.ModelForm):
    """
    Форма для создания и редактирования спутников.
    """
    
    class Meta:
        model = Satellite
        fields = [
            'name',
            'alternative_name',
            'location_place',
            'norad',
            'international_code',
            'band',
            'undersat_point',
            'url',
            'comment',
            'launch_date',
        ]
        widgets = {
            'name': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': 'Введите название спутника',
                'required': True
            }),
            'alternative_name': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': 'Введите альтернативное название (необязательно)'
            }),
            'location_place': forms.Select(attrs={
                'class': 'form-select'
            }),
            'norad': forms.NumberInput(attrs={
                'class': 'form-control',
                'placeholder': 'Введите NORAD ID'
            }),
            'international_code': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': 'Например, 2011-074A'
            }),
            'band': forms.SelectMultiple(attrs={
                'class': 'form-select',
                'size': '5'
            }),
            'undersat_point': forms.NumberInput(attrs={
                'class': 'form-control',
                'step': '0.01',
                'placeholder': 'Введите подспутниковую точку в градусах'
            }),
            'url': forms.URLInput(attrs={
                'class': 'form-control',
                'placeholder': 'https://example.com'
            }),
            'comment': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 3,
                'placeholder': 'Введите комментарий'
            }),
            'launch_date': forms.DateInput(attrs={
                'class': 'form-control',
                'type': 'date'
            }),
        }
        labels = {
            'name': 'Название спутника',
            'alternative_name': 'Альтернативное название',
            'location_place': 'Комплекс',
            'norad': 'NORAD ID',
            'international_code': 'Международный код',
            'band': 'Диапазоны работы',
            'undersat_point': 'Подспутниковая точка (градусы)',
            'url': 'Ссылка на источник',
            'comment': 'Комментарий',
            'launch_date': 'Дата запуска',
        }
        help_texts = {
            'name': 'Уникальное название спутника',
            'alternative_name': 'Альтернативное название спутника (например, на другом языке)',
            'location_place': 'К какому комплексу принадлежит спутник',
            'norad': 'Идентификатор NORAD для отслеживания спутника',
            'international_code': 'Международный идентификатор спутника (например, 2011-074A)',
            'band': 'Выберите диапазоны работы спутника (удерживайте Ctrl для множественного выбора)',
            'undersat_point': 'Восточное полушарие с +, западное с -',
            'url': 'Ссылка на сайт, где можно проверить информацию',
            'launch_date': 'Дата запуска спутника',
        }
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        from mainapp.models import Band
        
        # Загружаем choices для select полей
        self.fields['band'].queryset = Band.objects.all().order_by('name')
        
        # Делаем name обязательным
        self.fields['name'].required = True
    
    def clean_name(self):
        """Валидация поля name."""
        name = self.cleaned_data.get('name')
        
        if name:
            # Удаляем лишние пробелы
            name = name.strip()
            
            # Проверяем что после удаления пробелов что-то осталось
            if not name:
                raise forms.ValidationError('Название не может состоять только из пробелов')
            
            # Проверяем уникальность (исключая текущий объект при редактировании)
            qs = Satellite.objects.filter(name=name)
            if self.instance and self.instance.pk:
                qs = qs.exclude(pk=self.instance.pk)
            
            if qs.exists():
                raise forms.ValidationError('Спутник с таким названием уже существует')
        
        return name


class SourceRequestForm(forms.ModelForm):
    """
    Форма для создания и редактирования заявок на источники.
    """
    
    # Дополнительные поля для координат ГСО
    coords_lat = forms.FloatField(
        required=False,
        label='Широта ГСО',
        widget=forms.NumberInput(attrs={
            'class': 'form-control',
            'step': '0.000001',
            'placeholder': 'Например: 55.751244'
        })
    )
    coords_lon = forms.FloatField(
        required=False,
        label='Долгота ГСО',
        widget=forms.NumberInput(attrs={
            'class': 'form-control',
            'step': '0.000001',
            'placeholder': 'Например: 37.618423'
        })
    )
    
    # Дополнительные поля для координат источника
    coords_source_lat = forms.FloatField(
        required=False,
        label='Широта источника',
        widget=forms.NumberInput(attrs={
            'class': 'form-control',
            'step': '0.000001',
            'placeholder': 'Например: 55.751244'
        })
    )
    coords_source_lon = forms.FloatField(
        required=False,
        label='Долгота источника',
        widget=forms.NumberInput(attrs={
            'class': 'form-control',
            'step': '0.000001',
            'placeholder': 'Например: 37.618423'
        })
    )
    
    # Дополнительные поля для координат объекта
    coords_object_lat = forms.FloatField(
        required=False,
        label='Широта объекта',
        widget=forms.NumberInput(attrs={
            'class': 'form-control',
            'step': '0.000001',
            'placeholder': 'Например: 55.751244'
        })
    )
    coords_object_lon = forms.FloatField(
        required=False,
        label='Долгота объекта',
        widget=forms.NumberInput(attrs={
            'class': 'form-control',
            'step': '0.000001',
            'placeholder': 'Например: 37.618423'
        })
    )
    
    class Meta:
        from .models import SourceRequest
        model = SourceRequest
        fields = [
            'source',
            'satellite',
            'status',
            'priority',
            'planned_at',
            'request_date',
            'card_date',
            'downlink',
            'uplink',
            'transfer',
            'region',
            'gso_success',
            'kubsat_success',
            'comment',
        ]
        widgets = {
            'source': forms.Select(attrs={
                'class': 'form-select',
            }),
            'satellite': forms.Select(attrs={
                'class': 'form-select',
            }),
            'status': forms.Select(attrs={
                'class': 'form-select'
            }),
            'priority': forms.Select(attrs={
                'class': 'form-select'
            }),
            'planned_at': forms.DateTimeInput(attrs={
                'class': 'form-control',
                'type': 'datetime-local'
            }),
            'request_date': forms.DateInput(attrs={
                'class': 'form-control',
                'type': 'date'
            }),
            'card_date': forms.DateInput(attrs={
                'class': 'form-control',
                'type': 'date'
            }),
            'downlink': forms.NumberInput(attrs={
                'class': 'form-control',
                'step': '0.01',
                'placeholder': 'Частота downlink в МГц'
            }),
            'uplink': forms.NumberInput(attrs={
                'class': 'form-control',
                'step': '0.01',
                'placeholder': 'Частота uplink в МГц'
            }),
            'transfer': forms.NumberInput(attrs={
                'class': 'form-control',
                'step': '0.01',
                'placeholder': 'Перенос в МГц'
            }),
            'region': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': 'Район/местоположение'
            }),
            'gso_success': forms.Select(
                choices=[(None, '-'), (True, 'Да'), (False, 'Нет')],
                attrs={'class': 'form-select'}
            ),
            'kubsat_success': forms.Select(
                choices=[(None, '-'), (True, 'Да'), (False, 'Нет')],
                attrs={'class': 'form-select'}
            ),
            'comment': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 3,
                'placeholder': 'Введите комментарий'
            }),
        }
        labels = {
            'source': 'Источник',
            'satellite': 'Спутник',
            'status': 'Статус',
            'priority': 'Приоритет',
            'planned_at': 'Дата и время планирования',
            'request_date': 'Дата заявки',
            'card_date': 'Дата формирования карточки',
            'downlink': 'Частота Downlink (МГц)',
            'uplink': 'Частота Uplink (МГц)',
            'transfer': 'Перенос (МГц)',
            'region': 'Район',
            'gso_success': 'ГСО успешно?',
            'kubsat_success': 'Кубсат успешно?',
            'comment': 'Комментарий',
        }
    
    def __init__(self, *args, **kwargs):
        # Извлекаем source_id если передан
        source_id = kwargs.pop('source_id', None)
        super().__init__(*args, **kwargs)
        
        # Загружаем queryset для источников и спутников
        self.fields['source'].queryset = Source.objects.all().order_by('-id')
        self.fields['source'].required = False
        self.fields['satellite'].queryset = Satellite.objects.all().order_by('name')
        
        # Если передан source_id, устанавливаем его как начальное значение
        if source_id:
            self.fields['source'].initial = source_id
            # Можно сделать поле только для чтения
            self.fields['source'].widget.attrs['readonly'] = True
            
            # Пытаемся заполнить данные из источника
            try:
                source = Source.objects.get(pk=source_id)
                self._fill_from_source(source)
            except Source.DoesNotExist:
                pass
        
        # Настраиваем виджеты для булевых полей
        self.fields['gso_success'].widget = forms.Select(
            choices=[(None, '-'), (True, 'Да'), (False, 'Нет')],
            attrs={'class': 'form-select'}
        )
        self.fields['kubsat_success'].widget = forms.Select(
            choices=[(None, '-'), (True, 'Да'), (False, 'Нет')],
            attrs={'class': 'form-select'}
        )
        
        # Заполняем координаты из существующего объекта
        if self.instance and self.instance.pk:
            if self.instance.coords:
                self.fields['coords_lat'].initial = self.instance.coords.y
                self.fields['coords_lon'].initial = self.instance.coords.x
            if self.instance.coords_source:
                self.fields['coords_source_lat'].initial = self.instance.coords_source.y
                self.fields['coords_source_lon'].initial = self.instance.coords_source.x
            if self.instance.coords_object:
                self.fields['coords_object_lat'].initial = self.instance.coords_object.y
                self.fields['coords_object_lon'].initial = self.instance.coords_object.x
    
    def _fill_from_source(self, source):
        """Заполняет поля формы данными из источника и его связанных объектов."""
        # Получаем первую точку источника с транспондером
        objitem = source.source_objitems.select_related(
            'transponder', 'transponder__sat_id', 'parameter_obj'
        ).filter(transponder__isnull=False).first()
        
        if objitem and objitem.transponder:
            transponder = objitem.transponder
            # Заполняем данные из транспондера
            if transponder.downlink:
                self.fields['downlink'].initial = transponder.downlink
            if transponder.uplink:
                self.fields['uplink'].initial = transponder.uplink
            if transponder.transfer:
                self.fields['transfer'].initial = transponder.transfer
            if transponder.sat_id:
                self.fields['satellite'].initial = transponder.sat_id.pk
        
        # Координаты из источника
        if source.coords_average:
            self.fields['coords_lat'].initial = source.coords_average.y
            self.fields['coords_lon'].initial = source.coords_average.x
    
    def save(self, commit=True):
        from django.contrib.gis.geos import Point
        
        instance = super().save(commit=False)
        
        # Обрабатываем координаты ГСО
        coords_lat = self.cleaned_data.get('coords_lat')
        coords_lon = self.cleaned_data.get('coords_lon')
        
        if coords_lat is not None and coords_lon is not None:
            instance.coords = Point(coords_lon, coords_lat, srid=4326)
        elif coords_lat is None and coords_lon is None:
            instance.coords = None
        
        # Обрабатываем координаты источника
        coords_source_lat = self.cleaned_data.get('coords_source_lat')
        coords_source_lon = self.cleaned_data.get('coords_source_lon')
        
        if coords_source_lat is not None and coords_source_lon is not None:
            instance.coords_source = Point(coords_source_lon, coords_source_lat, srid=4326)
        elif coords_source_lat is None and coords_source_lon is None:
            instance.coords_source = None
        
        # Обрабатываем координаты объекта
        coords_object_lat = self.cleaned_data.get('coords_object_lat')
        coords_object_lon = self.cleaned_data.get('coords_object_lon')
        
        if coords_object_lat is not None and coords_object_lon is not None:
            instance.coords_object = Point(coords_object_lon, coords_object_lat, srid=4326)
        elif coords_object_lat is None and coords_object_lon is None:
            instance.coords_object = None
        
        if commit:
            instance.save()
        
        return instance
