from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
from django.shortcuts import get_object_or_404
from django.db.models import Q
from django.db import models
from decimal import Decimal, InvalidOperation
from .models import (
    Room, RoomMembership, CommunityPost,
    PostReaction, PostComment, CommentReaction,
    BiasharaListing, Message as CommunityMessage,
    Deal, KaziJob, Event, EventRSVP, LostFound,
)
from .serializers import CommunityPostSerializer, PostCommentSerializer


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


# ── ROOM LIST + CREATE ──
class RoomListView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        rooms = Room.objects.filter(is_active=True).order_by("room_type", "name")
        data  = []
        for room in rooms:
            membership = RoomMembership.objects.filter(room=room, user=request.user).first()
            data.append({
                "id": room.id, "name": room.name, "slug": room.slug,
                "description": room.description, "room_type": room.room_type,
                "icon": room.icon, "neighborhood": room.neighborhood,
                "is_private": room.is_private, "is_active": room.is_active,
                "member_count": RoomMembership.objects.filter(room=room).count(),
                "is_member": membership is not None,
                "created_by": room.created_by.username if room.created_by else None,
                "last_message": self._last_msg(room),
            })
        return Response(data)

    def _last_msg(self, room):
        post = CommunityPost.objects.filter(room=room, is_deleted=False).order_by("-created_at").first()
        if post:
            return {"content": post.content[:60], "username": post.author.username, "created_at": post.created_at}
        return None

    def post(self, request):
        name    = request.data.get("name", "").strip()
        desc    = request.data.get("description", "").strip()
        rtype   = request.data.get("room_type", "user")
        icon    = request.data.get("icon", "💬")
        hood    = request.data.get("neighborhood", "")
        private = request.data.get("is_private", False)
        if not name:
            return Response({"error": "Room name is required."}, status=400)
        if len(name) < 3:
            return Response({"error": "Name must be at least 3 characters."}, status=400)
        if not request.user.is_staff:
            rtype = "user"
        room = Room.objects.create(
            name=name, description=desc, room_type=rtype,
            icon=icon, neighborhood=hood, is_private=private,
            created_by=request.user, is_active=True,
        )
        RoomMembership.objects.create(user=request.user, room=room, role="admin")
        return Response({
            "id": room.id, "name": room.name, "slug": room.slug,
            "description": room.description, "room_type": room.room_type,
            "icon": room.icon, "neighborhood": room.neighborhood,
            "is_private": room.is_private, "is_active": room.is_active,
            "member_count": 1, "is_member": True,
            "created_by": room.created_by.username, "last_message": None,
        }, status=201)


# ── ADMIN ROOM MANAGEMENT ──
class AdminRoomManageView(APIView):
    permission_classes = [IsAuthenticated]

    def _is_room_admin(self, request, room):
        if request.user.is_staff:
            return True
        return RoomMembership.objects.filter(room=room, user=request.user, role="admin").exists()

    def patch(self, request, slug):
        room = get_object_or_404(Room, slug=slug)
        if not self._is_room_admin(request, room):
            return Response({"error": "Not authorized."}, status=403)
        action = request.data.get("action")
        if action == "activate":
            room.is_active = True; room.save(update_fields=["is_active"])
            return Response({"message": "Room activated."})
        elif action == "deactivate":
            room.is_active = False; room.save(update_fields=["is_active"])
            return Response({"message": "Room deactivated."})
        for field in ["name", "description", "icon", "neighborhood", "is_private"]:
            if field in request.data:
                setattr(room, field, request.data[field])
        room.save()
        return Response({"message": "Room updated."})

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


# ── LEAVE ROOM ──
class LeaveRoomView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request, slug):
        room = get_object_or_404(Room, slug=slug)
        if room.created_by == request.user:
            return Response({"error": "You created this room. Delete it instead."}, status=400)
        membership = RoomMembership.objects.filter(room=room, user=request.user).first()
        if not membership:
            return Response({"error": "You are not a member."}, status=400)
        membership.delete()
        room.member_count = RoomMembership.objects.filter(room=room).count()
        room.save(update_fields=["member_count"])
        return Response({"message": "Left #" + room.name + "."})


# ── ROOM FEED ──
class RoomFeedView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def get(self, request, slug):
        room = get_object_or_404(Room, slug=slug, is_active=True)
        membership, created = RoomMembership.objects.get_or_create(
            user=request.user, room=room, defaults={"role": "member"}
        )
        if created and room.created_by and room.created_by != request.user:
            notify(
                recipient=room.created_by, notif_type="room_join",
                title=request.user.username + " joined " + room.name,
                body="New member in your room",
                link="/user/chats/" + room.slug, sender=request.user,
            )
        posts = CommunityPost.objects.filter(
            room=room, is_deleted=False
        ).select_related("author").prefetch_related("reactions", "comments")
        return Response(CommunityPostSerializer(posts, many=True, context={"request": request}).data)

    def post(self, request, slug):
        room = get_object_or_404(Room, slug=slug, is_active=True)
        serializer = CommunityPostSerializer(data=request.data, context={"request": request})
        if serializer.is_valid():
            post = serializer.save(author=request.user, room=room)
            members = RoomMembership.objects.filter(room=room).exclude(user=request.user).select_related("user")
            for m in members:
                notify(
                    recipient=m.user, notif_type="announcement",
                    title=request.user.username + " posted in " + room.name,
                    body=post.content[:60] if post.content else "",
                    link="/user/chats/" + room.slug, sender=request.user,
                )
            return Response(serializer.data, status=201)
        return Response(serializer.errors, status=400)


# ── ROOM MEMBERS ──
class RoomMembersView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, slug):
        room = get_object_or_404(Room, slug=slug, is_active=True)
        memberships = RoomMembership.objects.filter(room=room).select_related("user")
        return Response([{"id": m.user.id, "username": m.user.username, "role": m.role} for m in memberships])


# ── POST DETAIL ──
class PostDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def delete(self, request, post_id):
        post = get_object_or_404(CommunityPost, id=post_id, is_deleted=False)
        if post.author != request.user and not request.user.is_staff:
            return Response({"detail": "Not authorized."}, status=403)
        post.is_deleted = True
        post.save(update_fields=["is_deleted"])
        return Response({"detail": "Post deleted."})


# ── POST REACTION ──
class PostReactionView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request, post_id):
        post          = get_object_or_404(CommunityPost, id=post_id, is_deleted=False)
        reaction_type = request.data.get("reaction_type", "like")
        existing      = PostReaction.objects.filter(post=post, user=request.user).first()
        if existing:
            if existing.reaction_type == reaction_type:
                existing.delete(); action = "removed"
            else:
                existing.reaction_type = reaction_type; existing.save(); action = "updated"
        else:
            PostReaction.objects.create(post=post, user=request.user, reaction_type=reaction_type)
            action = "added"
            if post.author != request.user:
                notify(
                    recipient=post.author, notif_type="post_reaction",
                    title=request.user.username + " reacted to your post",
                    body=post.content[:60] if post.content else "",
                    link="/user/chats/" + post.room.slug, sender=request.user,
                )
        return Response({"action": action, "reaction_counts": post.reaction_counts()})


# ── POST COMMENTS ──
class PostCommentsView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, post_id):
        post     = get_object_or_404(CommunityPost, id=post_id, is_deleted=False)
        comments = PostComment.objects.filter(
            post=post, is_deleted=False, parent=None
        ).select_related("author").prefetch_related("replies", "comment_reactions")
        return Response(PostCommentSerializer(comments, many=True, context={"request": request}).data)

    def post(self, request, post_id):
        post = get_object_or_404(CommunityPost, id=post_id, is_deleted=False)
        serializer = PostCommentSerializer(data=request.data, context={"request": request})
        if serializer.is_valid():
            parent_id = request.data.get("parent_id")
            parent    = PostComment.objects.filter(id=parent_id).first() if parent_id else None
            comment   = serializer.save(author=request.user, post=post, parent=parent)
            if post.author != request.user:
                notify(
                    recipient=post.author, notif_type="post_comment",
                    title=request.user.username + " commented on your post 💬",
                    body=comment.content[:60] if comment.content else "",
                    link="/user/chats/" + post.room.slug, sender=request.user,
                )
            return Response(serializer.data, status=201)
        return Response(serializer.errors, status=400)


# ── COMMENT DELETE ──
class CommentDeleteView(APIView):
    permission_classes = [IsAuthenticated]

    def delete(self, request, comment_id):
        comment = get_object_or_404(PostComment, id=comment_id, is_deleted=False)
        if comment.author != request.user and not request.user.is_staff:
            return Response({"detail": "Not authorized."}, status=403)
        comment.is_deleted = True
        comment.save(update_fields=["is_deleted"])
        return Response({"detail": "Comment deleted."})


# ── COMMENT REACTION ──
class CommentReactionView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request, comment_id):
        comment       = get_object_or_404(PostComment, id=comment_id, is_deleted=False)
        reaction_type = request.data.get("reaction_type", "like")
        existing      = CommentReaction.objects.filter(comment=comment, user=request.user).first()
        if existing:
            if existing.reaction_type == reaction_type:
                existing.delete(); action = "removed"
            else:
                existing.reaction_type = reaction_type; existing.save(); action = "updated"
        else:
            CommentReaction.objects.create(comment=comment, user=request.user, reaction_type=reaction_type)
            action = "added"
        return Response({"action": action, "reaction_counts": comment.reaction_counts()})


# ── BIASHARA HELPERS ──
def _safe_decimal(val):
    if val is None: return None
    try: return Decimal(str(val).strip())
    except (InvalidOperation, ValueError, TypeError): return None


def _serialize_listing(l, request):
    def img_url(field):
        if not field: return None
        try: return request.build_absolute_uri(field.url)
        except: return "http://127.0.0.1:8000" + field.url
    return {
        "id": l.id, "title": l.title, "description": l.description,
        "price": str(l.price) if l.price else None,
        "price_label": l.price_label, "price_display": l.get_price_display(),
        "category": l.category, "location": l.location, "phone": l.phone,
        "status": l.status, "image": img_url(l.image),
        "image2": img_url(l.image2), "image3": img_url(l.image3),
        "seller": l.seller.username, "seller_id": l.seller.id,
        "views_count": l.views_count, "created_at": l.created_at, "room_id": l.room_id,
    }


# ── BIASHARA LIST + CREATE ──
class BiasharaListingListView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def get(self, request):
        qs = BiasharaListing.objects.filter(status="active").select_related("seller")
        category = request.query_params.get("category")
        if category: qs = qs.filter(category=category)
        location = request.query_params.get("location")
        if location: qs = qs.filter(location__icontains=location)
        search = request.query_params.get("search", "").strip()
        if search: qs = qs.filter(Q(title__icontains=search) | Q(description__icontains=search))
        return Response([_serialize_listing(l, request) for l in qs])

    def post(self, request):
        title       = request.data.get("title", "").strip()
        description = request.data.get("description", "").strip()
        price_raw   = request.data.get("price")
        price_label = request.data.get("price_label", "").strip()
        category    = request.data.get("category", "other")
        location    = request.data.get("location", "").strip()
        phone       = request.data.get("phone", "").strip()
        room_id     = request.data.get("room_id")
        if not title or not description:
            return Response({"error": "Title and description are required."}, status=400)
        listing = BiasharaListing(
            seller=request.user, title=title, description=description,
            category=category, location=location, phone=phone, price_label=price_label,
        )
        price = _safe_decimal(price_raw)
        if price is not None: listing.price = price
        if "image"  in request.FILES: listing.image  = request.FILES["image"]
        if "image2" in request.FILES: listing.image2 = request.FILES["image2"]
        if "image3" in request.FILES: listing.image3 = request.FILES["image3"]
        if room_id:
            room = Room.objects.filter(id=room_id, room_type="business", is_active=True).first()
            if room: listing.room = room
        listing.save()
        if listing.room:
            img_part = ""
            if listing.image:
                img_part = "\nImage: http://127.0.0.1:8000" + listing.image.url
            msg_text = (
                "NEW LISTING: " + listing.title + "\n\n" + listing.description + "\n\n" +
                "Price: " + listing.get_price_display() + "\n" +
                "Location: " + (listing.location or "Thika") + "\n" +
                "Contact: " + (listing.phone or "Message via inbox") + img_part
            )
            CommunityMessage.objects.create(room=listing.room, user=request.user, content=msg_text)
        return Response(_serialize_listing(listing, request), status=201)


# ── BIASHARA DETAIL ──
class BiasharaListingDetailView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def get(self, request, pk):
        l = get_object_or_404(BiasharaListing, pk=pk)
        BiasharaListing.objects.filter(pk=pk).update(views_count=l.views_count + 1)
        l.refresh_from_db()
        return Response(_serialize_listing(l, request))

    def patch(self, request, pk):
        l = get_object_or_404(BiasharaListing, pk=pk)
        if l.seller != request.user and not request.user.is_staff:
            return Response({"error": "Not authorized."}, status=403)
        for field in ["title","description","price_label","category","location","phone","status"]:
            val = request.data.get(field)
            if val is not None and str(val).strip() != "":
                setattr(l, field, str(val).strip())
        price_raw = request.data.get("price")
        if price_raw is not None and str(price_raw).strip() != "":
            price = _safe_decimal(price_raw)
            if price is not None: l.price = price
        if "image"  in request.FILES: l.image  = request.FILES["image"]
        if "image2" in request.FILES: l.image2 = request.FILES["image2"]
        if "image3" in request.FILES: l.image3 = request.FILES["image3"]
        try: l.save()
        except Exception as e: return Response({"error": "Save failed: " + str(e)}, status=400)
        return Response(_serialize_listing(l, request))

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


# ── DEALS ──
def _serialize_deal(d, request):
    def img_url(field):
        if not field: return None
        try: return request.build_absolute_uri(field.url)
        except: return "http://127.0.0.1:8000" + field.url
    from django.utils import timezone
    return {
        "id": d.id, "title": d.title, "description": d.description,
        "original_price": str(d.original_price) if d.original_price else None,
        "deal_price":     str(d.deal_price)     if d.deal_price     else None,
        "discount_percent": d.discount_percent(),
        "category": d.category, "location": d.location, "phone": d.phone,
        "image": img_url(d.image), "expires_at": d.expires_at,
        "is_expired": d.is_expired(), "seller": d.seller.username,
        "seller_id": d.seller.id, "views_count": d.views_count,
        "created_at": d.created_at,
    }


class DealListView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def get(self, request):
        from django.utils import timezone
        qs = Deal.objects.filter(is_active=True, expires_at__gt=timezone.now()).select_related("seller")
        category = request.query_params.get("category")
        if category: qs = qs.filter(category=category)
        search = request.query_params.get("search", "").strip()
        if search: qs = qs.filter(Q(title__icontains=search) | Q(description__icontains=search))
        return Response([_serialize_deal(d, request) for d in qs])

    def post(self, request):
        from django.utils import timezone
        title       = request.data.get("title", "").strip()
        description = request.data.get("description", "").strip()
        if not title or not description:
            return Response({"error": "Title and description required."}, status=400)
        expires_in = int(request.data.get("expires_in", 6))
        deal = Deal(
            seller=request.user, title=title, description=description,
            category=request.data.get("category", "other"),
            location=request.data.get("location", "").strip(),
            phone=request.data.get("phone", "").strip(),
            expires_at=timezone.now() + timezone.timedelta(hours=expires_in),
        )
        orig   = _safe_decimal(request.data.get("original_price"))
        dprice = _safe_decimal(request.data.get("deal_price"))
        if orig:   deal.original_price = orig
        if dprice: deal.deal_price     = dprice
        if "image" in request.FILES: deal.image = request.FILES["image"]
        deal.save()
        try:
            from account.models import User as UserModel
            from notifications.utils import create_notification
            for u in UserModel.objects.exclude(id=request.user.id)[:50]:
                create_notification(
                    recipient=u, sender=request.user, notif_type="announcement",
                    title="🔥 New Deal: " + deal.title,
                    body=deal.description[:60], link="/user/biashara",
                )
        except Exception:
            pass
        return Response(_serialize_deal(deal, request), status=201)


class DealDetailView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def get(self, request, pk):
        deal = get_object_or_404(Deal, pk=pk)
        Deal.objects.filter(pk=pk).update(views_count=deal.views_count + 1)
        deal.refresh_from_db()
        return Response(_serialize_deal(deal, request))

    def patch(self, request, pk):
        deal = get_object_or_404(Deal, pk=pk)
        if deal.seller != request.user and not request.user.is_staff:
            return Response({"error": "Not authorized."}, status=403)
        for field in ["title","description","category","location","phone"]:
            val = request.data.get(field)
            if val: setattr(deal, field, str(val).strip())
        if "image" in request.FILES: deal.image = request.FILES["image"]
        deal.save()
        return Response(_serialize_deal(deal, request))

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


# ── KAZI JOBS ──
def _serialize_job(j, request):
    return {
        "id": j.id, "title": j.title, "description": j.description,
        "job_type": j.job_type, "category": j.category,
        "location": j.location, "neighborhood": j.neighborhood,
        "pay": j.pay, "phone": j.phone, "is_active": j.is_active,
        "poster": j.poster.username, "poster_id": j.poster.id,
        "created_at": j.created_at,
    }


class KaziJobListView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def get(self, request):
        qs = KaziJob.objects.filter(is_active=True).select_related("poster")
        category = request.query_params.get("category")
        if category: qs = qs.filter(category=category)
        job_type = request.query_params.get("job_type")
        if job_type: qs = qs.filter(job_type=job_type)
        hood = request.query_params.get("neighborhood")
        if hood: qs = qs.filter(neighborhood=hood)
        search = request.query_params.get("search", "").strip()
        if search: qs = qs.filter(Q(title__icontains=search) | Q(description__icontains=search))
        return Response([_serialize_job(j, request) for j in qs])

    def post(self, request):
        title       = request.data.get("title", "").strip()
        description = request.data.get("description", "").strip()
        if not title or not description:
            return Response({"error": "Title and description required."}, status=400)
        job = KaziJob.objects.create(
            poster=request.user, title=title, description=description,
            job_type=request.data.get("job_type", "casual"),
            category=request.data.get("category", "other"),
            location=request.data.get("location", "").strip(),
            neighborhood=request.data.get("neighborhood", "").strip(),
            pay=request.data.get("pay", "").strip(),
            phone=request.data.get("phone", "").strip(),
        )
        return Response(_serialize_job(job, request), status=201)


class KaziJobDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, pk):
        job = get_object_or_404(KaziJob, pk=pk)
        return Response(_serialize_job(job, request))

    def patch(self, request, pk):
        job = get_object_or_404(KaziJob, pk=pk)
        if job.poster != request.user and not request.user.is_staff:
            return Response({"error": "Not authorized."}, status=403)
        for field in ["title","description","job_type","category","location","neighborhood","pay","phone","is_active"]:
            val = request.data.get(field)
            if val is not None: setattr(job, field, val)
        job.save()
        return Response(_serialize_job(job, request))

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


# ── EVENTS ──
def _serialize_event(e, request):
    def img_url(field):
        if not field: return None
        try: return request.build_absolute_uri(field.url)
        except: return "http://127.0.0.1:8000" + field.url
    return {
        "id": e.id, "title": e.title, "description": e.description,
        "category": e.category, "location": e.location,
        "neighborhood": e.neighborhood, "starts_at": e.starts_at,
        "ends_at": e.ends_at, "is_free": e.is_free,
        "ticket_price": str(e.ticket_price) if e.ticket_price else None,
        "phone": e.phone, "image": img_url(e.image),
        "is_active": e.is_active, "rsvp_count": e.rsvp_count,
        "organizer": e.organizer.username, "organizer_id": e.organizer.id,
        "created_at": e.created_at,
    }


class EventListView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def get(self, request):
        from django.utils import timezone
        now = timezone.now()
        # Show all active events that are upcoming
        # BUT also show past events that the current user organized (so they can edit/reschedule)
        qs = Event.objects.filter(is_active=True).select_related("organizer")
        qs = qs.filter(
            models.Q(starts_at__gt=now) |
            models.Q(organizer=request.user)
        )
        category = request.query_params.get("category")
        if category: qs = qs.filter(category=category)
        search = request.query_params.get("search", "").strip()
        if search: qs = qs.filter(Q(title__icontains=search) | Q(description__icontains=search))
        return Response([_serialize_event(e, request) for e in qs.order_by("starts_at")])

    def post(self, request):
        title       = request.data.get("title", "").strip()
        description = request.data.get("description", "").strip()
        location    = request.data.get("location", "").strip()
        starts_at   = request.data.get("starts_at")
        if not title or not description or not location or not starts_at:
            return Response({"error": "Title, description, location and start date required."}, status=400)
        event = Event(
            organizer=request.user, title=title, description=description,
            location=location,
            neighborhood=request.data.get("neighborhood", "").strip(),
            category=request.data.get("category", "other"),
            starts_at=starts_at,
            ends_at=request.data.get("ends_at") or None,
            is_free=str(request.data.get("is_free", True)).lower() in ("true", "1", "yes"),
            phone=request.data.get("phone", "").strip(),
        )
        price = _safe_decimal(request.data.get("ticket_price"))
        if price: event.ticket_price = price
        if "image" in request.FILES: event.image = request.FILES["image"]
        event.save()
        return Response(_serialize_event(event, request), status=201)


class EventDetailView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def get(self, request, pk):
        event = get_object_or_404(Event, pk=pk)
        return Response(_serialize_event(event, request))

    def patch(self, request, pk):
        event = get_object_or_404(Event, pk=pk)
        if event.organizer != request.user and not request.user.is_staff:
            return Response({"error": "Not authorized."}, status=403)
        for field in ["title","description","location","neighborhood","category","phone","is_free","is_active"]:
            val = request.data.get(field)
            if val is not None: setattr(event, field, val)
        if "image" in request.FILES: event.image = request.FILES["image"]
        event.save()
        return Response(_serialize_event(event, request))

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


class EventRSVPView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request, pk):
        event = get_object_or_404(Event, pk=pk)
        rsvp, created = EventRSVP.objects.get_or_create(event=event, user=request.user)
        if not created:
            rsvp.delete()
            Event.objects.filter(pk=pk).update(rsvp_count=event.rsvp_count - 1)
            return Response({"rsvped": False, "rsvp_count": event.rsvp_count - 1})
        Event.objects.filter(pk=pk).update(rsvp_count=event.rsvp_count + 1)
        return Response({"rsvped": True, "rsvp_count": event.rsvp_count + 1})


# ── LOST & FOUND ──
def _serialize_lostfound(l, request):
    def img_url(field):
        if not field: return None
        try: return request.build_absolute_uri(field.url)
        except: return "http://127.0.0.1:8000" + field.url
    return {
        "id": l.id, "title": l.title, "description": l.description,
        "post_type": l.post_type, "category": l.category,
        "location": l.location, "neighborhood": l.neighborhood,
        "phone": l.phone, "reward": l.reward,
        "image": img_url(l.image), "is_resolved": l.is_resolved,
        "poster": l.poster.username, "poster_id": l.poster.id,
        "created_at": l.created_at,
    }


class LostFoundListView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def get(self, request):
        qs = LostFound.objects.filter(is_resolved=False).select_related("poster")
        post_type = request.query_params.get("post_type")
        if post_type: qs = qs.filter(post_type=post_type)
        category = request.query_params.get("category")
        if category: qs = qs.filter(category=category)
        search = request.query_params.get("search", "").strip()
        if search: qs = qs.filter(Q(title__icontains=search) | Q(description__icontains=search))
        return Response([_serialize_lostfound(l, request) for l in qs])

    def post(self, request):
        title       = request.data.get("title", "").strip()
        description = request.data.get("description", "").strip()
        post_type   = request.data.get("post_type", "lost")
        if not title or not description:
            return Response({"error": "Title and description required."}, status=400)
        lf = LostFound(
            poster=request.user, title=title, description=description,
            post_type=post_type,
            category=request.data.get("category", "item"),
            location=request.data.get("location", "").strip(),
            neighborhood=request.data.get("neighborhood", "").strip(),
            phone=request.data.get("phone", "").strip(),
            reward=request.data.get("reward", "").strip(),
        )
        if "image" in request.FILES: lf.image = request.FILES["image"]
        lf.save()
        return Response(_serialize_lostfound(lf, request), status=201)


class LostFoundDetailView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def get(self, request, pk):
        lf = get_object_or_404(LostFound, pk=pk)
        return Response(_serialize_lostfound(lf, request))

    def patch(self, request, pk):
        lf = get_object_or_404(LostFound, pk=pk)
        if lf.poster != request.user and not request.user.is_staff:
            return Response({"error": "Not authorized."}, status=403)
        for field in ["title","description","category","location","neighborhood","phone","reward","is_resolved"]:
            val = request.data.get(field)
            if val is not None: setattr(lf, field, val)
        if "image" in request.FILES: lf.image = request.FILES["image"]
        lf.save()
        return Response(_serialize_lostfound(lf, request))

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

# ── CAMPUS ──
# campus models imported inline below

UNIVERSITY_LABELS = {
    "mku":"Mount Kenya University","dkut":"Dedan Kimathi University",
    "kca":"KCA University","other":"Other",
}



# ── BUSINESS PROFILES ──
from .models import (
    BusinessProfile, BusinessService, BusinessPost, BusinessFollower,
    CampusResource, HostelListing, AttachmentPost,
)
from notifications.utils import create_notification

UNIVERSITY_LABELS = {
    "mku":"Mount Kenya University","dkut":"Dedan Kimathi University",
    "kca":"KCA University","other":"Other",
}

def _img(field, request):
    if not field: return None
    try: return request.build_absolute_uri(field.url)
    except: return "http://127.0.0.1:8000" + field.url

def _serialize_business(b, request, user=None):
    is_following = False
    if user and user.is_authenticated:
        is_following = BusinessFollower.objects.filter(business=b, user=user).exists()
    return {
        "id": b.id, "shop_name": b.shop_name, "slug": b.slug,
        "category": b.category, "description": b.description,
        "address": b.address, "neighborhood": b.neighborhood,
        "near_campus": b.near_campus, "phone": b.phone,
        "whatsapp": b.whatsapp, "email": b.email,
        "logo": _img(b.logo, request), "cover_image": _img(b.cover_image, request),
        "is_verified": b.is_verified, "is_active": b.is_active,
        "followers_count": b.followers_count,
        "owner_id": b.owner.id, "owner": b.owner.username,
        "is_following": is_following,
        "room_slug": b.room.slug if b.room else None,
        "created_at": b.created_at,
        "services": [{"id":s.id,"name":s.name,"description":s.description,"price":s.price} for s in b.services.all()],
    }

def _serialize_business_post(p, request):
    return {
        "id": p.id, "title": p.title, "body": p.body,
        "image": _img(p.image, request), "is_deal": p.is_deal,
        "business_id": p.business.id, "business_name": p.business.shop_name,
        "business_slug": p.business.slug, "is_verified": p.business.is_verified,
        "created_at": p.created_at,
    }

def _serialize_resource(r, request):
    return {
        "id": r.id, "title": r.title, "description": r.description,
        "resource_type": r.resource_type, "university": r.university,
        "university_label": UNIVERSITY_LABELS.get(r.university, r.university),
        "unit_code": r.unit_code, "course": r.course, "year": r.year,
        "price": str(r.price) if r.price else None, "is_free": r.is_free,
        "phone": r.phone, "file_url": r.file_url,
        "image": _img(r.image, request), "downloads": r.downloads,
        "posted_by": r.posted_by.username, "posted_by_id": r.posted_by.id,
        "business": {"id": r.business.id, "name": r.business.shop_name, "slug": r.business.slug, "is_verified": r.business.is_verified} if r.business else None,
        "created_at": r.created_at,
    }

def _serialize_hostel(h, request):
    return {
        "id": h.id, "title": h.title, "description": h.description,
        "hostel_type": h.hostel_type, "near_campus": h.near_campus,
        "university_label": UNIVERSITY_LABELS.get(h.near_campus, h.near_campus),
        "location": h.location, "distance": h.distance,
        "price": str(h.price) if h.price else None,
        "phone": h.phone, "image": _img(h.image, request),
        "is_available": h.is_available,
        "landlord": h.landlord.username, "landlord_id": h.landlord.id,
        "created_at": h.created_at,
    }

def _serialize_attachment(a, request):
    return {
        "id": a.id, "company": a.company, "title": a.title,
        "description": a.description, "location": a.location,
        "course": a.course, "duration": a.duration, "deadline": a.deadline,
        "phone": a.phone, "email": a.email, "is_active": a.is_active,
        "posted_by": a.posted_by.username, "posted_by_id": a.posted_by.id,
        "created_at": a.created_at,
    }


# ── Business Profile CRUD ──
class BusinessProfileListView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def get(self, request):
        qs = BusinessProfile.objects.filter(is_active=True).prefetch_related("services")
        cat = request.query_params.get("category")
        if cat: qs = qs.filter(category=cat)
        campus = request.query_params.get("near_campus")
        if campus: qs = qs.filter(near_campus=campus)
        search = request.query_params.get("search","").strip()
        if search: qs = qs.filter(Q(shop_name__icontains=search)|Q(description__icontains=search))
        return Response([_serialize_business(b, request, request.user) for b in qs])

    def post(self, request):
        if BusinessProfile.objects.filter(owner=request.user).exists():
            return Response({"error": "You already have a business profile."}, status=400)
        name = request.data.get("shop_name","").strip()
        desc = request.data.get("description","").strip()
        addr = request.data.get("address","").strip()
        if not name or not desc or not addr:
            return Response({"error": "Shop name, description and address required."}, status=400)
        b = BusinessProfile(
            owner=request.user, shop_name=name, description=desc, address=addr,
            category=request.data.get("category","other"),
            neighborhood=request.data.get("neighborhood","").strip(),
            near_campus=request.data.get("near_campus",""),
            phone=request.data.get("phone","").strip(),
            whatsapp=request.data.get("whatsapp","").strip(),
            email=request.data.get("email","").strip(),
        )
        if "logo" in request.FILES: b.logo = request.FILES["logo"]
        if "cover_image" in request.FILES: b.cover_image = request.FILES["cover_image"]
        b.save()
        # Auto-create a chatroom for the business
        try:
            from .models import Room, RoomMembership
            room = Room.objects.create(
                name=name,
                icon="🏪",
                room_type="business",
                created_by=request.user,
                description=f"Official chatroom for {name}",
            )
            # Add owner as member
            RoomMembership.objects.create(room=room, user=request.user, role="admin")
            b.room = room
            b.save(update_fields=["room"])
        except Exception as e:
            print(f"Room creation error: {e}")
        # Add services
        services_raw = request.data.get("services","")
        if services_raw:
            import json
            try:
                svcs = json.loads(services_raw) if isinstance(services_raw, str) else services_raw
                for s in svcs:
                    BusinessService.objects.create(business=b, name=s.get("name",""), price=s.get("price",""), description=s.get("description",""))
            except: pass
        return Response(_serialize_business(b, request, request.user), status=201)


class BusinessProfileDetailView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def get(self, request, slug):
        b = get_object_or_404(BusinessProfile, slug=slug)
        return Response(_serialize_business(b, request, request.user))

    def patch(self, request, slug):
        b = get_object_or_404(BusinessProfile, slug=slug)
        if b.owner != request.user and not request.user.is_staff:
            return Response({"error": "Not authorized."}, status=403)
        for field in ["shop_name","description","address","category","neighborhood","near_campus","phone","whatsapp","email"]:
            val = request.data.get(field)
            if val is not None: setattr(b, field, val)
        if "logo" in request.FILES: b.logo = request.FILES["logo"]
        if "cover_image" in request.FILES: b.cover_image = request.FILES["cover_image"]
        b.save()
        return Response(_serialize_business(b, request, request.user))

    def delete(self, request, slug):
        b = get_object_or_404(BusinessProfile, slug=slug)
        if b.owner != request.user and not request.user.is_staff:
            return Response({"error": "Not authorized."}, status=403)
        b.delete()
        return Response(status=204)


class BusinessFollowView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request, slug):
        b = get_object_or_404(BusinessProfile, slug=slug)
        if b.owner == request.user:
            return Response({"error": "Cannot follow your own business."}, status=400)
        obj, created = BusinessFollower.objects.get_or_create(business=b, user=request.user)
        if created:
            BusinessProfile.objects.filter(pk=b.pk).update(followers_count=models.F("followers_count")+1)
            create_notification(b.owner, "business_follow", f"{request.user.username} followed your business {b.shop_name}", request.user)
            # Auto-join follower to business chatroom
            if b.room:
                from .models import RoomMembership
                RoomMembership.objects.get_or_create(room=b.room, user=request.user, defaults={"role":"member"})
            b.refresh_from_db()
            return Response({"following": True, "followers_count": b.followers_count, "room_slug": b.room.slug if b.room else None})
        else:
            obj.delete()
            BusinessProfile.objects.filter(pk=b.pk).update(followers_count=models.F("followers_count")-1)
            # Remove from chatroom
            if b.room:
                from .models import RoomMembership
                RoomMembership.objects.filter(room=b.room, user=request.user).delete()
            b.refresh_from_db()
            return Response({"following": False, "followers_count": b.followers_count, "room_slug": b.room.slug if b.room else None})


class BusinessPostListView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def get(self, request, slug):
        b = get_object_or_404(BusinessProfile, slug=slug)
        posts = b.posts.all()
        return Response([_serialize_business_post(p, request) for p in posts])

    def post(self, request, slug):
        b = get_object_or_404(BusinessProfile, slug=slug)
        if b.owner != request.user:
            return Response({"error": "Not authorized."}, status=403)
        title = request.data.get("title","").strip()
        body  = request.data.get("body","").strip()
        if not title or not body:
            return Response({"error": "Title and body required."}, status=400)
        p = BusinessPost(business=b, title=title, body=body,
            is_deal=str(request.data.get("is_deal","false")).lower() in ("true","1"))
        if "image" in request.FILES: p.image = request.FILES["image"]
        p.save()
        # Notify followers
        for f in b.followers.select_related("user"):
            create_notification(f.user, "business_post", f"{b.shop_name} posted: {title}", request.user)
        return Response(_serialize_business_post(p, request), status=201)


class BusinessPostDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def delete(self, request, slug, pk):
        b = get_object_or_404(BusinessProfile, slug=slug)
        p = get_object_or_404(BusinessPost, pk=pk, business=b)
        if b.owner != request.user and not request.user.is_staff:
            return Response({"error": "Not authorized."}, status=403)
        p.delete()
        return Response(status=204)


# ── Business Feed (all posts from all businesses) ──
class BusinessFeedView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        posts = BusinessPost.objects.select_related("business").order_by("-created_at")[:50]
        return Response([_serialize_business_post(p, request) for p in posts])


# ── Campus Resources ──
class CampusResourceListView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def get(self, request):
        qs = CampusResource.objects.select_related("posted_by","business")
        rtype = request.query_params.get("resource_type")
        if rtype: qs = qs.filter(resource_type=rtype)
        uni = request.query_params.get("university")
        if uni: qs = qs.filter(university=uni)
        search = request.query_params.get("search","").strip()
        if search: qs = qs.filter(Q(title__icontains=search)|Q(unit_code__icontains=search)|Q(course__icontains=search))
        return Response([_serialize_resource(r, request) for r in qs])

    def post(self, request):
        title = request.data.get("title","").strip()
        if not title:
            return Response({"error": "Title required."}, status=400)
        r = CampusResource(
            posted_by=request.user, title=title,
            description=request.data.get("description","").strip(),
            resource_type=request.data.get("resource_type","other"),
            university=request.data.get("university","mku"),
            unit_code=request.data.get("unit_code","").strip(),
            course=request.data.get("course","").strip(),
            year=request.data.get("year","").strip(),
            phone=request.data.get("phone","").strip(),
            file_url=request.data.get("file_url","").strip(),
            is_free=str(request.data.get("is_free","true")).lower() in ("true","1"),
        )
        price = _safe_decimal(request.data.get("price"))
        if price: r.price = price
        # Link to business if owner has one
        try: r.business = request.user.business_profile
        except: pass
        if "image" in request.FILES: r.image = request.FILES["image"]
        r.save()
        return Response(_serialize_resource(r, request), status=201)


class CampusResourceDetailView(APIView):
    permission_classes = [IsAuthenticated]

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


# ── Hostels ──
class HostelListView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def get(self, request):
        qs = HostelListing.objects.filter(is_available=True).select_related("landlord")
        campus = request.query_params.get("near_campus")
        if campus: qs = qs.filter(near_campus=campus)
        htype = request.query_params.get("hostel_type")
        if htype: qs = qs.filter(hostel_type=htype)
        search = request.query_params.get("search","").strip()
        if search: qs = qs.filter(Q(title__icontains=search)|Q(location__icontains=search))
        return Response([_serialize_hostel(h, request) for h in qs])

    def post(self, request):
        title = request.data.get("title","").strip()
        desc  = request.data.get("description","").strip()
        loc   = request.data.get("location","").strip()
        price = _safe_decimal(request.data.get("price"))
        if not title or not desc or not loc or not price:
            return Response({"error": "Title, description, location and price required."}, status=400)
        h = HostelListing(
            landlord=request.user, title=title, description=desc,
            location=loc, price=price,
            near_campus=request.data.get("near_campus","mku"),
            hostel_type=request.data.get("hostel_type","bedsitter"),
            distance=request.data.get("distance","").strip(),
            phone=request.data.get("phone","").strip(),
        )
        if "image" in request.FILES: h.image = request.FILES["image"]
        h.save()
        return Response(_serialize_hostel(h, request), status=201)


class HostelDetailView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def patch(self, request, pk):
        h = get_object_or_404(HostelListing, pk=pk)
        if h.landlord != request.user and not request.user.is_staff:
            return Response({"error": "Not authorized."}, status=403)
        for field in ["title","description","hostel_type","near_campus","location","distance","phone","is_available"]:
            val = request.data.get(field)
            if val is not None: setattr(h, field, val)
        price = _safe_decimal(request.data.get("price"))
        if price: h.price = price
        if "image" in request.FILES: h.image = request.FILES["image"]
        h.save()
        return Response(_serialize_hostel(h, request))

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


# ── Attachments ──
class AttachmentListView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes     = [MultiPartParser, FormParser, JSONParser]

    def get(self, request):
        qs = AttachmentPost.objects.filter(is_active=True).select_related("posted_by")
        search = request.query_params.get("search","").strip()
        if search: qs = qs.filter(Q(title__icontains=search)|Q(company__icontains=search))
        return Response([_serialize_attachment(a, request) for a in qs])

    def post(self, request):
        title   = request.data.get("title","").strip()
        company = request.data.get("company","").strip()
        desc    = request.data.get("description","").strip()
        if not title or not company or not desc:
            return Response({"error": "Title, company and description required."}, status=400)
        a = AttachmentPost.objects.create(
            posted_by=request.user, title=title, company=company, description=desc,
            location=request.data.get("location","").strip(),
            course=request.data.get("course","").strip(),
            duration=request.data.get("duration","").strip(),
            deadline=request.data.get("deadline") or None,
            phone=request.data.get("phone","").strip(),
            email=request.data.get("email","").strip(),
        )
        return Response(_serialize_attachment(a, request), status=201)


class AttachmentDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def patch(self, request, pk):
        a = get_object_or_404(AttachmentPost, pk=pk)
        if a.posted_by != request.user and not request.user.is_staff:
            return Response({"error": "Not authorized."}, status=403)
        for field in ["title","company","description","location","course","duration","phone","email","is_active"]:
            val = request.data.get(field)
            if val is not None: setattr(a, field, val)
        if request.data.get("deadline"): a.deadline = request.data.get("deadline")
        a.save()
        return Response(_serialize_attachment(a, request))

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


class BusinessServiceListView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request, slug):
        b = get_object_or_404(BusinessProfile, slug=slug)
        if b.owner != request.user:
            return Response({"error": "Not authorized."}, status=403)
        name = request.data.get("name","").strip()
        if not name:
            return Response({"error": "Name required."}, status=400)
        s = BusinessService.objects.create(
            business=b, name=name,
            description=request.data.get("description","").strip(),
            price=request.data.get("price","").strip(),
        )
        return Response({"id":s.id,"name":s.name,"description":s.description,"price":s.price}, status=201)


class BusinessServiceDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def delete(self, request, slug, pk):
        b = get_object_or_404(BusinessProfile, slug=slug)
        if b.owner != request.user:
            return Response({"error": "Not authorized."}, status=403)
        s = get_object_or_404(BusinessService, pk=pk, business=b)
        s.delete()
        return Response(status=204)


class BusinessFollowersListView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, slug):
        b = get_object_or_404(BusinessProfile, slug=slug)
        followers = BusinessFollower.objects.filter(business=b).select_related("user")
        data = []
        for f in followers:
            u = f.user
            data.append({
                "id": u.id,
                "username": u.username,
                "profile_image": request.build_absolute_uri(u.profile_image.url) if u.profile_image else None,
                "neighborhood": u.neighborhood,
                "joined": f.created_at,
            })
        return Response(data)
