from rest_framework import status
from rest_framework.viewsets import ViewSet
from rest_framework.permissions import IsAuthenticated
from drf_spectacular.utils import extend_schema, OpenApiResponse, OpenApiExample, inline_serializer, OpenApiParameter
from rest_framework import serializers
from rest_framework.decorators import action
from rest_framework.response import Response
from django.http import HttpResponse
from django.db.models import Case, When, IntegerField
from api.account.serializers.alert_serializers import AlertSerializer
from sitemanagement.models import Alert
from api.utils.decorators import handle_exceptions
from api.utils.error_serializer import ErrorResponseSerializer
from api.utils.report_generators import generate_csv_report, generate_pdf_report
from django.utils import timezone

@extend_schema(tags=['Алерты'])
class AlertView(ViewSet):
    # permission_classes = [IsAuthenticated]
    
    @extend_schema(
        summary="Получение списка алертов",
        description="Возвращает список алертов в системе с фильтрацией по уровню тревоги. Алерты сортируются: сначала warning, затем critical",
        parameters=[
            OpenApiParameter(
                name='severity',
                description='Фильтр по уровню тревоги',
                required=False,
                type=str,
                enum=['warning', 'critical']
            )
        ],
        responses={
            200: OpenApiResponse(response=AlertSerializer(many=True), description="Список алертов успешно получен",
                               examples=[OpenApiExample(
                                   'Успешный ответ',
                                   value=[{
                                       "id": 1,
                                       "name": "Датчик 1",
                                       "object": "Объект 1",
                                       "metric_value": "12.5 °C",
                                       "sensor_type_name": "Инклинометр",
                                       "message": "alert message",
                                       "severity": "warning",
                                       "created_at": "2025-10-06T15:53:11.759725+03:00",
                                       "resolved": False
                                   }]
                               )])
        })
    
    @action(detail=False, methods=['get'])
    @handle_exceptions
    def get_alerts(self, request):
        alerts = Alert.objects.all()
        
        # фильтрация по severity
        severity = request.query_params.get('severity')
        if severity and severity in ['warning', 'critical']:
            alerts = alerts.filter(severity=severity)
        
        # сортировка: warning первыми, потом critical
        alerts = alerts.annotate(
            severity_order=Case(
                When(severity='critical', then=1),
                When(severity='warning', then=2),
                default=3,
                output_field=IntegerField()
            )
        ).order_by('severity_order', '-created_at')
        
        serializer = AlertSerializer(alerts, many=True)
        return Response(serializer.data)

    @extend_schema(
        summary="Изменение статуса алерта",
        description="Изменяет статус обработки алерта на противоположный",
        responses={
            200: OpenApiResponse(response=AlertSerializer, description="Статус алерта успешно изменен",
                               examples=[OpenApiExample(
                                   'Успешный ответ',
                                   value={
                                       "message": "Статус алерта успешно изменен"
                                   }
                               )]),
            404: OpenApiResponse(
                response=ErrorResponseSerializer,
                description="Алерт не найден", 
                examples=[
                    OpenApiExample(
                        'Алерт не найден',
                        value={"error": "Алерт не найден"},
                        status_codes=['404']
                    )
                ]
            )
        })
    @action(detail=True, methods=['patch'])
    @handle_exceptions
    def change_alert_status(self, request, pk=None):
        try:
            alert = Alert.objects.get(pk=pk)
            alert.resolved = not alert.resolved
            alert.save()
            
            return Response({"message": "Статус алерта успешно изменен"}, status=status.HTTP_200_OK)
            
        except Alert.DoesNotExist:
            return Response(
                {"error": "Алерт не найден"}, 
                status=status.HTTP_404_NOT_FOUND)
            
@extend_schema(tags=['Репорты'])
class ReportView(ViewSet):
    permission_classes = [IsAuthenticated]
    
    @extend_schema(
        summary="Генерация отчета",
        description="Генерирует отчет в выбранном формате (PDF или CSV)",
        request={'application/json': {'type': 'object', 'properties': {
            'report_format': {'type': 'string', 'enum': ['pdf', 'csv']},
            'hours': {'type': 'integer', 'description': 'Количество часов для фильтрации по времени'},
            'detector_ids': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Список ID датчиков для фильтрации (может быть числом или строкой вида "GLE-79")'}
        }}},
        methods=['POST'],
        responses={
            200: OpenApiResponse(
                response=inline_serializer(
                    name='BinaryFile',
                    fields={
                        'file': serializers.FileField()
                    }
                ),
                description="Файл отчета для скачивания в формате PDF или CSV"
            ),
            400: OpenApiResponse(
                response=ErrorResponseSerializer,
                description="Неверный формат",
                examples=[OpenApiExample(
                    'Неверный формат',
                    value={"error": "Неверный формат"},
                    status_codes=['400']
                )]
            )
        })
    @action(detail=False, methods=['post'])
    @handle_exceptions
    def get_reports(self, request):
        """Генерация отчета в выбранном формате"""
        report_format = request.data.get('report_format', '').lower()
        
        if not report_format:
            report_format = request.query_params.get('format', '').lower()
        
        if report_format not in ["pdf", "csv"]:
            return Response(
                {"error": "Неверный формат. Допустимые значения: pdf, csv"}, 
                status=status.HTTP_400_BAD_REQUEST
            )
        
        # Получаем параметры фильтрации
        hours = request.data.get('hours')
        detector_ids = request.data.get('detector_ids', [])
        
        alerts = Alert.objects.select_related(
            'sensor',
            'sensor__signal_format',
            'sensor_type',
            'metric'
        ).prefetch_related(
            'sensor__zones',
            'sensor__zones__object'
        ).all()
        
        # Фильтрация по времени (если указано количество часов)
        if hours and isinstance(hours, (int, float)) and hours > 0:
            from datetime import timedelta
            cutoff_time = timezone.now() - timedelta(hours=hours)
            alerts = alerts.filter(created_at__gte=cutoff_time)
        
        # Фильтрация по датчикам (если указаны ID)
        if detector_ids and isinstance(detector_ids, list) and len(detector_ids) > 0:
            # Конвертируем строковые ID в числовые ID базы данных
            numeric_ids = []
            for detector_id in detector_ids:
                if isinstance(detector_id, (int, float)):
                    numeric_ids.append(int(detector_id))
                elif isinstance(detector_id, str):
                    # Парсим строковые ID вида "GLE-79" или "GA-123"
                    try:
                        if '-' in detector_id:
                            # Формат "TYPE-ID" - извлекаем числовую часть
                            numeric_ids.append(int(detector_id.split('-')[-1]))
                        else:
                            # Предполагаем, что это просто число в строковом формате
                            numeric_ids.append(int(detector_id))
                    except (ValueError, IndexError):
                        # Пропускаем некорректные ID
                        continue
            
            if numeric_ids:
                alerts = alerts.filter(sensor_id__in=numeric_ids)
        
        # текущая дата для имени файла
        timestamp = timezone.now().strftime("%Y%m%d_%H%M%S")
        
        if report_format == "csv":
            response = HttpResponse(content_type='text/csv')
            response['Content-Disposition'] = f'attachment; filename="alerts_report_{timestamp}.csv"'
            response.write(generate_csv_report(alerts))
            return response
            
        else:  # pdf
            response = HttpResponse(content_type='application/pdf')
            response['Content-Disposition'] = f'attachment; filename="alerts_report_{timestamp}.pdf"'
            response.write(generate_pdf_report(alerts))
            return response