"""Listing CRUD + search endpoints.""" from __future__ import annotations from typing import Optional from fastapi import APIRouter, BackgroundTasks, Depends, Query from app.middleware.auth import get_current_user, get_optional_user, require_admin from app.schemas.listing import ( ListingCreate, ListingListResponse, ListingResponse, ListingStatusUpdate, ListingUpdate, ) from app.services.agency_service import AgencyService from app.services.listing_service import ListingService router = APIRouter(prefix="/listings", tags=["Listings"]) # ── Public ─────────────────────────────────────────────── @router.get("/", response_model=ListingListResponse) def list_listings( search: Optional[str] = None, category: Optional[str] = None, agency_id: Optional[str] = None, min_price: Optional[float] = None, max_price: Optional[float] = None, location: Optional[str] = None, listing_type: Optional[str] = None, condition: Optional[str] = None, sort_by: str = Query("newest"), page: int = Query(1, ge=1), page_size: int = Query(20, ge=1, le=100), ): svc = ListingService() return svc.list_listings( search=search, category=category, agency_id=agency_id, min_price=min_price, max_price=max_price, location=location, listing_type=listing_type, condition=condition, sort_by=sort_by, page=page, page_size=page_size, status="approved", ) @router.get("/featured", response_model=ListingListResponse) def featured_listings(): """Return top 8 most viewed approved listings.""" svc = ListingService() return svc.list_listings( sort_by="popular", page=1, page_size=8, status="approved", ) @router.get("/{listing_id}", response_model=ListingResponse) def get_listing( listing_id: str, background_tasks: BackgroundTasks, user: Optional[dict] = Depends(get_optional_user), ): svc = ListingService() listing = svc.get_listing(listing_id) background_tasks.add_task(svc.increment_views, listing_id) return listing # ── Agency ─────────────────────────────────────────────── @router.get("/agency/mine", response_model=ListingListResponse) def my_listings( status: Optional[str] = None, page: int = Query(1, ge=1), page_size: int = Query(20, ge=1, le=100), user: dict = Depends(get_current_user), ): agency_svc = AgencyService() agency = agency_svc.get_agency_by_user(user["id"]) svc = ListingService() return svc.list_listings( agency_id=agency["id"], status=status, page=page, page_size=page_size, ) @router.post("/", response_model=ListingResponse, status_code=201) def create_listing(body: ListingCreate, user: dict = Depends(get_current_user)): agency_svc = AgencyService() agency = agency_svc.get_agency_by_user(user["id"]) svc = ListingService() return svc.create_listing(agency["id"], body.model_dump()) @router.patch("/{listing_id}", response_model=ListingResponse) def update_listing( listing_id: str, body: ListingUpdate, user: dict = Depends(get_current_user), ): svc = ListingService() return svc.update_listing( listing_id, user["id"], user["role"], body.model_dump(exclude_unset=True) ) @router.delete("/{listing_id}") def delete_listing(listing_id: str, user: dict = Depends(get_current_user)): svc = ListingService() return svc.delete_listing(listing_id, user["id"], user["role"]) # ── Admin ──────────────────────────────────────────────── @router.get("/admin/all", response_model=ListingListResponse) def admin_list_all( status: Optional[str] = None, search: Optional[str] = None, category: Optional[str] = None, min_price: Optional[float] = None, max_price: Optional[float] = None, location: Optional[str] = None, listing_type: Optional[str] = None, page: int = Query(1, ge=1), page_size: int = Query(20, ge=1, le=100), _admin: dict = Depends(require_admin), ): svc = ListingService() return svc.list_listings( search=search, status=status, category=category, min_price=min_price, max_price=max_price, location=location, listing_type=listing_type, page=page, page_size=page_size, ) @router.patch("/{listing_id}/status", response_model=ListingResponse) def update_listing_status( listing_id: str, body: ListingStatusUpdate, _admin: dict = Depends(require_admin), ): svc = ListingService() return svc.update_status(listing_id, body.status, body.rejection_reason) @router.get("/stats/overview") def listing_stats( agency_id: Optional[str] = None, user: dict = Depends(get_current_user), ): svc = ListingService() if user["role"] != "admin": # Non-admins always see their own agency's stats only agency_svc = AgencyService() try: agency = agency_svc.get_agency_by_user(user["id"]) agency_id = agency["id"] except Exception: return {"total": 0, "pending": 0, "approved": 0, "rejected": 0} return svc.get_stats(agency_id)