"""
ViewSets for Incident management API endpoints.
"""

from django.utils import timezone
from django_filters.rest_framework import DjangoFilterBackend
from drf_spectacular.utils import extend_schema, extend_schema_view
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import IsAdminUser
from rest_framework.response import Response

from apps.core.models import Incident, IncidentAlert, RateLimitAlert, SystemAlert

from .incident_serializers import (
    IncidentAcknowledgeSerializer,
    IncidentAlertSerializer,
    IncidentCreateSerializer,
    IncidentResolveSerializer,
    IncidentSerializer,
    LinkAlertsSerializer,
)


@extend_schema_view(
    list=extend_schema(
        summary="List incidents",
        description="Get all incidents, optionally filtered by status or severity.",
        tags=["Admin - Incidents"],
    ),
    retrieve=extend_schema(
        summary="Get incident",
        description="Get details of a specific incident including linked alerts.",
        tags=["Admin - Incidents"],
    ),
    create=extend_schema(
        summary="Create incident",
        description="Create a new incident and optionally link alerts.",
        tags=["Admin - Incidents"],
    ),
    update=extend_schema(
        summary="Update incident",
        description="Update an existing incident.",
        tags=["Admin - Incidents"],
    ),
    partial_update=extend_schema(
        summary="Partial update incident",
        description="Partially update an existing incident.",
        tags=["Admin - Incidents"],
    ),
    destroy=extend_schema(
        summary="Delete incident",
        description="Delete an incident.",
        tags=["Admin - Incidents"],
    ),
)
class IncidentViewSet(viewsets.ModelViewSet):
    """
    ViewSet for managing incidents.

    Provides CRUD operations plus acknowledge, resolve, and alert linking actions.
    """

    queryset = Incident.objects.prefetch_related("linked_alerts").all()
    permission_classes = [IsAdminUser]
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    filterset_fields = ["status", "severity"]
    search_fields = ["title", "description", "incident_number"]
    ordering_fields = ["detected_at", "severity", "status", "alert_count"]
    ordering = ["-detected_at"]

    def get_serializer_class(self):
        if self.action == "create":
            return IncidentCreateSerializer
        if self.action == "acknowledge":
            return IncidentAcknowledgeSerializer
        if self.action == "resolve":
            return IncidentResolveSerializer
        if self.action == "link_alerts":
            return LinkAlertsSerializer
        if self.action == "alerts":
            return IncidentAlertSerializer
        return IncidentSerializer

    @extend_schema(
        summary="Acknowledge incident",
        description="Mark an incident as being investigated.",
        request=IncidentAcknowledgeSerializer,
        responses={200: IncidentSerializer},
        tags=["Admin - Incidents"],
    )
    @action(detail=True, methods=["post"])
    def acknowledge(self, request, pk=None):
        """Mark an incident as being investigated."""
        incident = self.get_object()

        if incident.status != Incident.Status.OPEN:
            return Response(
                {"detail": f"Cannot acknowledge incident in '{incident.status}' status"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        incident.status = Incident.Status.INVESTIGATING
        incident.acknowledged_at = timezone.now()
        incident.acknowledged_by = request.user
        incident.save()

        return Response(IncidentSerializer(incident).data)

    @extend_schema(
        summary="Resolve incident",
        description="Mark an incident as resolved, optionally resolving all linked alerts.",
        request=IncidentResolveSerializer,
        responses={200: IncidentSerializer},
        tags=["Admin - Incidents"],
    )
    @action(detail=True, methods=["post"])
    def resolve(self, request, pk=None):
        """Mark an incident as resolved."""
        incident = self.get_object()

        if incident.status in (Incident.Status.RESOLVED, Incident.Status.CLOSED):
            return Response(
                {"detail": "Incident is already resolved or closed"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        serializer = IncidentResolveSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        incident.status = Incident.Status.RESOLVED
        incident.resolved_at = timezone.now()
        incident.resolved_by = request.user
        incident.resolution_notes = serializer.validated_data.get("resolution_notes", "")
        incident.save()

        # Optionally resolve all linked alerts
        if serializer.validated_data.get("resolve_alerts", True):
            now = timezone.now()
            for link in incident.linked_alerts.all():
                if link.alert_source == "system":
                    SystemAlert.objects.filter(
                        id=link.alert_id, resolved_at__isnull=True
                    ).update(resolved_at=now, resolved_by=request.user)
                elif link.alert_source == "rate_limit":
                    RateLimitAlert.objects.filter(
                        id=link.alert_id, resolved_at__isnull=True
                    ).update(resolved_at=now, resolved_by=request.user)

        return Response(IncidentSerializer(incident).data)

    @extend_schema(
        summary="Get linked alerts",
        description="Get all alerts linked to this incident.",
        responses={200: IncidentAlertSerializer(many=True)},
        tags=["Admin - Incidents"],
    )
    @action(detail=True, methods=["get"])
    def alerts(self, request, pk=None):
        """Get all alerts linked to this incident."""
        incident = self.get_object()
        alerts = incident.linked_alerts.all()
        serializer = IncidentAlertSerializer(alerts, many=True)
        return Response(serializer.data)

    @extend_schema(
        summary="Link alerts to incident",
        description="Link additional alerts to an existing incident.",
        request=LinkAlertsSerializer,
        responses={200: IncidentSerializer},
        tags=["Admin - Incidents"],
    )
    @action(detail=True, methods=["post"], url_path="link-alerts")
    def link_alerts(self, request, pk=None):
        """Link additional alerts to an incident."""
        incident = self.get_object()

        serializer = LinkAlertsSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        alert_ids = serializer.validated_data["alert_ids"]
        alert_sources = serializer.validated_data["alert_sources"]

        created = 0
        for alert_id, source in zip(alert_ids, alert_sources):
            _, was_created = IncidentAlert.objects.get_or_create(
                incident=incident,
                alert_id=alert_id,
                alert_source=source,
            )
            if was_created:
                created += 1

        # Refresh to get updated alert_count
        incident.refresh_from_db()

        return Response({
            "detail": f"Linked {created} new alerts to incident",
            "incident": IncidentSerializer(incident).data,
        })
