"""
LyngSat related views for data synchronization and linking.
"""
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import redirect, render
from django.urls import reverse_lazy
from django.views import View
from django.views.generic import FormView

from ..forms import FillLyngsatDataForm, LinkLyngsatForm
from ..mixins import FormMessageMixin
from ..models import ObjItem


class LinkLyngsatSourcesView(LoginRequiredMixin, FormMessageMixin, FormView):
    """View for linking LyngSat sources to objects."""
    
    template_name = "mainapp/link_lyngsat.html"
    form_class = LinkLyngsatForm
    success_message = "Привязка источников LyngSat завершена"
    error_message = "Ошибка при привязке источников"

    def form_valid(self, form):
        from lyngsatapp.models import LyngSat
        
        satellites = form.cleaned_data.get("satellites")
        frequency_tolerance = form.cleaned_data.get("frequency_tolerance", 0.5)
        
        # If satellites not selected, process all
        if satellites:
            objitems = ObjItem.objects.filter(
                parameter_obj__id_satellite__in=satellites
            ).select_related('parameter_obj', 'parameter_obj__polarization')
        else:
            objitems = ObjItem.objects.filter(
                parameter_obj__isnull=False
            ).select_related('parameter_obj', 'parameter_obj__polarization')
        
        linked_count = 0
        total_count = objitems.count()
        
        for objitem in objitems:
            if not hasattr(objitem, 'parameter_obj') or not objitem.parameter_obj:
                continue
                
            param = objitem.parameter_obj
            
            # Round object frequency to 1 decimal place
            if param.frequency:
                rounded_freq = round(param.frequency, 1)  # Round to 1 decimal place
                
                # Find matching LyngSat source
                # Compare by rounded frequency (with tolerance) and polarization
                # LyngSat frequencies are also rounded to 1 decimal place for comparison
                lyngsat_sources = LyngSat.objects.filter(
                    id_satellite=param.id_satellite,
                    polarization=param.polarization
                ).select_related('id_satellite', 'polarization')
                
                # Filter by rounded frequency with tolerance
                matching_sources = []
                for lyngsat in lyngsat_sources:
                    if lyngsat.frequency:
                        rounded_lyngsat_freq = round(lyngsat.frequency, 1)
                        if abs(rounded_lyngsat_freq - rounded_freq) <= frequency_tolerance:
                            matching_sources.append(lyngsat)
                
                if matching_sources:
                    # Take first matching source (sorted by frequency difference)
                    matching_sources.sort(key=lambda x: abs(round(x.frequency, 1) - rounded_freq))
                    objitem.lyngsat_source = matching_sources[0]
                    objitem.save(update_fields=['lyngsat_source'])
                    
                    # Update Source with ObjectInfo and ObjectOwnership for TV
                    if objitem.source:
                        from ..models import ObjectInfo, ObjectOwnership
                        try:
                            tv_type = ObjectInfo.objects.get(name="Стационарные")
                            tv_ownership = ObjectOwnership.objects.get(name="ТВ")
                            
                            # Update source if not already set
                            if not objitem.source.info:
                                objitem.source.info = tv_type
                            if not objitem.source.ownership:
                                objitem.source.ownership = tv_ownership
                            
                            objitem.source.save(update_fields=['info', 'ownership'])
                        except (ObjectInfo.DoesNotExist, ObjectOwnership.DoesNotExist):
                            # If types don't exist, skip this step
                            pass
                    
                    linked_count += 1
        
        messages.success(
            self.request,
            f"Привязано {linked_count} из {total_count} объектов к источникам LyngSat"
        )
        return redirect("mainapp:link_lyngsat")

    def form_invalid(self, form):
        return self.render_to_response(self.get_context_data(form=form))


class FillLyngsatDataView(LoginRequiredMixin, FormMessageMixin, FormView):
    """
    View for filling data from Lyngsat.
    
    Allows selecting satellites and regions for parsing data from Lyngsat website.
    Starts asynchronous Celery task for processing.
    """
    template_name = "mainapp/fill_lyngsat_data.html"
    form_class = FillLyngsatDataForm
    success_url = reverse_lazy("mainapp:lyngsat_task_status")
    error_message = "Форма заполнена некорректно"

    def form_valid(self, form):
        satellites = form.cleaned_data["satellites"]
        regions = form.cleaned_data["regions"]
        use_cache = form.cleaned_data.get("use_cache", True)
        force_refresh = form.cleaned_data.get("force_refresh", False)
        
        # Get satellite names
        target_sats = [sat.name for sat in satellites]
        
        try:
            from lyngsatapp.tasks import fill_lyngsat_data_task
            
            # Start asynchronous task with caching parameters
            task = fill_lyngsat_data_task.delay(
                target_sats, 
                regions,
                force_refresh=force_refresh,
                use_cache=use_cache
            )
            
            cache_status = "без кеша" if not use_cache else ("с обновлением кеша" if force_refresh else "с кешированием")
            
            messages.success(
                self.request,
                f"Задача запущена ({cache_status})! ID задачи: {task.id}. "
                "Вы будете перенаправлены на страницу отслеживания прогресса."
            )
            
            # Redirect to task status page
            return redirect('mainapp:lyngsat_task_status', task_id=task.id)
            
        except Exception as e:
            messages.error(self.request, f"Ошибка при запуске задачи: {str(e)}")
            return redirect("mainapp:fill_lyngsat_data")


class LyngsatTaskStatusView(LoginRequiredMixin, View):
    """View for tracking Lyngsat data filling task status."""
    
    template_name = "mainapp/lyngsat_task_status.html"
    
    def get(self, request, task_id=None):
        context = {
            'task_id': task_id
        }
        return render(request, self.template_name, context)


class ClearLyngsatCacheView(LoginRequiredMixin, View):
    """View for clearing LyngSat cache."""
    
    def post(self, request):
        from lyngsatapp.tasks import clear_cache_task
        
        cache_type = request.POST.get('cache_type', 'all')
        
        try:
            # Start cache clearing task
            task = clear_cache_task.delay(cache_type)
            
            messages.success(
                request,
                f"Задача очистки кеша ({cache_type}) запущена! ID задачи: {task.id}"
            )
        except Exception as e:
            messages.error(request, f"Ошибка при запуске задачи очистки кеша: {str(e)}")
        
        return redirect(request.META.get('HTTP_REFERER', 'mainapp:source_list'))
    
    def get(self, request):
        """Cache management page."""
        return render(request, 'mainapp/clear_lyngsat_cache.html')


class UnlinkAllLyngsatSourcesView(LoginRequiredMixin, View):
    """View for unlinking all LyngSat sources from ObjItems."""
    
    def post(self, request):
        """Unlink all LyngSat sources."""
        try:
            # Count objects with LyngSat sources before unlinking
            linked_count = ObjItem.objects.filter(lyngsat_source__isnull=False).count()
            
            # Unlink all LyngSat sources
            ObjItem.objects.filter(lyngsat_source__isnull=False).update(lyngsat_source=None)
            
            messages.success(
                request,
                f"Успешно отвязано {linked_count} объектов от источников LyngSat"
            )
        except Exception as e:
            messages.error(request, f"Ошибка при отвязке источников: {str(e)}")
        
        return redirect('mainapp:actions')
    
    def get(self, request):
        """Show confirmation page."""
        # Count objects with LyngSat sources
        linked_count = ObjItem.objects.filter(lyngsat_source__isnull=False).count()
        
        context = {
            'linked_count': linked_count
        }
        return render(request, 'mainapp/unlink_lyngsat_confirm.html', context)
