from django.utils import timezone
from django.db.models import Q
from rest_framework import generics, permissions
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
from django.shortcuts import get_object_or_404
from .models import Announcement, AnnouncementView
from .serializers import AnnouncementSerializer


def get_active_qs():
    return Announcement.objects.filter(is_active=True).exclude(
        expires_at__isnull=False,
        expires_at__lt=timezone.now()
    )


def filter_by_hood(qs, user):
    hood = getattr(user, "neighborhood", None)
    if hood:
        return qs.filter(neighborhood__in=["all", hood])
    return qs.filter(neighborhood="all")


def notify(recipient, notif_type, title, body="", link="", sender=None):
    try:
        from notifications.utils import create_notification
        create_notification(
            recipient=recipient, notif_type=notif_type,
            title=title, body=body, link=link, sender=sender
        )
    except Exception:
        pass


class AnnouncementListView(generics.ListAPIView):
    serializer_class   = AnnouncementSerializer
    permission_classes = [permissions.IsAuthenticated]

    def get_queryset(self):
        qs = get_active_qs()
        category = self.request.query_params.get("category")
        if category and category != "all":
            qs = qs.filter(category=category)
        priority = self.request.query_params.get("priority")
        if priority and priority != "all":
            qs = qs.filter(priority=priority)
        neighborhood = self.request.query_params.get("neighborhood")
        if neighborhood and neighborhood != "all":
            qs = qs.filter(neighborhood__in=["all", neighborhood])
        else:
            qs = filter_by_hood(qs, self.request.user)
        search = self.request.query_params.get("search", "").strip()
        if search:
            qs = qs.filter(Q(title__icontains=search) | Q(body__icontains=search))
        return qs.order_by("-priority", "-created_at")

    def get_serializer_context(self):
        ctx = super().get_serializer_context()
        ctx["request"] = self.request
        return ctx


class AnnouncementDetailView(generics.RetrieveAPIView):
    serializer_class   = AnnouncementSerializer
    permission_classes = [permissions.IsAuthenticated]
    queryset           = Announcement.objects.filter(is_active=True)

    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        AnnouncementView.objects.get_or_create(announcement=instance, user=request.user)
        return Response(self.get_serializer(instance, context={"request": request}).data)


class AnnouncementsByCategory(generics.ListAPIView):
    serializer_class   = AnnouncementSerializer
    permission_classes = [permissions.IsAuthenticated]

    def get_queryset(self):
        qs = get_active_qs().filter(category=self.kwargs.get("category"))
        return filter_by_hood(qs, self.request.user)[:5]

    def get_serializer_context(self):
        ctx = super().get_serializer_context()
        ctx["request"] = self.request
        return ctx


class AnnouncementCreateView(APIView):
    permission_classes = [permissions.IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def post(self, request):
        title        = request.data.get("title", "").strip()
        body         = request.data.get("body", "").strip()
        category     = request.data.get("category", "general")
        neighborhood = request.data.get("neighborhood", "all")
        priority     = request.data.get("priority", "normal")
        link         = request.data.get("link", "").strip()
        expires_at   = request.data.get("expires_at") or None

        if not title or not body:
            return Response({"error": "Title and body required."}, status=400)

        ann = Announcement(
            title=title, body=body, category=category,
            neighborhood=neighborhood, priority=priority,
            link=link or None, expires_at=expires_at,
            created_by=request.user, is_active=True,
        )
        if "image" in request.FILES:
            ann.image = request.FILES["image"]
        ann.save()

        # Notify neighbourhood users for urgent/high priority
        if priority in ["urgent", "high"]:
            try:
                from account.models import User as UserModel
                from notifications.utils import create_notification
                qs = UserModel.objects.exclude(id=request.user.id)
                if neighborhood != "all":
                    qs = qs.filter(neighborhood=neighborhood)
                emoji = "🚨" if priority == "urgent" else "📢"
                for u in qs[:100]:
                    create_notification(
                        recipient=u, sender=request.user,
                        notif_type="announcement",
                        title=emoji + " " + title,
                        body=body[:80],
                        link="/user/explore?cat=" + category,
                    )
            except Exception:
                pass

        return Response(
            AnnouncementSerializer(ann, context={"request": request}).data,
            status=201
        )


class AnnouncementUpdateView(APIView):
    permission_classes = [permissions.IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def patch(self, request, pk):
        ann = get_object_or_404(Announcement, pk=pk)
        if ann.created_by != request.user and not request.user.is_staff:
            return Response({"error": "Not authorized."}, status=403)

        for field in ["title", "body", "category", "neighborhood", "priority", "link"]:
            val = request.data.get(field)
            if val is not None:
                setattr(ann, field, val)

        if "image" in request.FILES:
            ann.image = request.FILES["image"]

        expires_at = request.data.get("expires_at")
        if expires_at is not None:
            ann.expires_at = expires_at or None

        ann.save()
        return Response(AnnouncementSerializer(ann, context={"request": request}).data)


class AnnouncementDeleteView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def delete(self, request, pk):
        ann = get_object_or_404(Announcement, pk=pk)
        if ann.created_by != request.user and not request.user.is_staff:
            return Response({"error": "Not authorized."}, status=403)
        ann.delete()
        return Response(status=204)


class AnnouncementToggleView(APIView):
    """Hide or show an announcement."""
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, pk):
        ann = get_object_or_404(Announcement, pk=pk)
        if ann.created_by != request.user and not request.user.is_staff:
            return Response({"error": "Not authorized."}, status=403)
        ann.is_active = not ann.is_active
        ann.save(update_fields=["is_active"])
        return Response({"is_active": ann.is_active})


class DashboardWidgetsView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        now  = timezone.now()
        hood = getattr(request.user, "neighborhood", None)

        def fetch(category, limit=3):
            qs = Announcement.objects.filter(
                is_active=True, category=category,
            ).exclude(expires_at__isnull=False, expires_at__lt=now)
            if hood:
                qs = qs.filter(neighborhood__in=["all", hood])
            else:
                qs = qs.filter(neighborhood="all")
            return AnnouncementSerializer(
                qs.order_by("-priority", "-created_at")[:limit],
                many=True, context={"request": request}
            ).data

        # Also return created_by_id for owner controls
        return Response({
            "taarifa":  fetch("taarifa",  3),
            "shughuli": fetch("shughuli", 3),
            "biashara": fetch("biashara", 3),
            "kazi":     fetch("kazi",     3),
            "matatu":   fetch("matatu",   2),
            "harambee": fetch("harambee", 2),
        })


class ForwardAnnouncementView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, pk):
        try:
            announcement = Announcement.objects.get(pk=pk, is_active=True)
        except Announcement.DoesNotExist:
            return Response({"error": "Announcement not found."}, status=404)

        forward_type = request.data.get("type")
        sender       = request.user
        cat          = announcement.get_category_display().split("—")[0].strip().upper()
        text         = f"📢 [{cat}] {announcement.title}\n\n{announcement.body}"

        if announcement.link:
            text += f"\n\n🔗 {announcement.link}"
        if announcement.image:
            text += f"\n\n🖼 http://127.0.0.1:8000{announcement.image.url}"
        text += f"\n\n👉 View on ThikaConnect: http://localhost:5174/user/explore?cat={announcement.category}"

        if forward_type == "inbox":
            recipient_id = request.data.get("recipient_id")
            if not recipient_id:
                return Response({"error": "recipient_id required."}, status=400)
            try:
                from inbox.models import Conversation, Message as InboxMessage
                from account.models import User as UserModel
                recipient = UserModel.objects.get(pk=recipient_id)
                conv = Conversation.objects.filter(participants=sender).filter(participants=recipient).first()
                if not conv:
                    conv = Conversation.objects.create()
                    conv.participants.add(sender, recipient)
                    conv.save()
                InboxMessage.objects.create(conversation=conv, sender=sender, content=text)
                return Response({"message": f"Forwarded to {recipient.username}."})
            except UserModel.DoesNotExist:
                return Response({"error": "User not found."}, status=404)
            except Exception as e:
                return Response({"error": f"Inbox error: {str(e)}"}, status=400)

        elif forward_type == "room":
            room_id = request.data.get("room_id")
            if not room_id:
                return Response({"error": "room_id required."}, status=400)
            forwarded = False; last_error = ""
            try:
                from community.models import Room as CommunityRoom, Message as CommunityMessage
                room = CommunityRoom.objects.get(pk=room_id)
                CommunityMessage.objects.create(room=room, user=sender, content=text, is_announcement=True)
                forwarded = True
            except CommunityRoom.DoesNotExist:
                last_error = "Community room not found."
            except Exception as e:
                last_error = str(e)
            if not forwarded:
                try:
                    from chat.models import Room as ChatRoom, Message as ChatMessage
                    room = ChatRoom.objects.get(pk=room_id)
                    ChatMessage.objects.create(room=room, user=sender, content=text)
                    forwarded = True
                except Exception as e:
                    last_error = str(e)
            if forwarded:
                return Response({"message": "Forwarded to chat room."})
            return Response({"error": f"Room error: {last_error}"}, status=400)

        return Response({"error": "type must be 'inbox' or 'room'."}, status=400)
