from datetime import datetime, timezone from google.cloud.firestore_v1 import DocumentReference from shared.firebase import get_db from shared.exceptions import NotFoundError from helpdesk.models import HelpdeskMessage COLLECTION = "helpdesk" def _convert_firestore_value(val): """Convert Firestore-specific types to strings.""" if isinstance(val, datetime): return val.strftime("%d %B %Y at %H:%M:%S UTC%z") if isinstance(val, DocumentReference): return val.path return val def _resolve_sender(db, sender_ref) -> tuple[str, str]: """Resolve a sender DocumentReference to (sender_id, sender_name).""" sender_id = "" sender_name = "" try: if isinstance(sender_ref, DocumentReference): doc = sender_ref.get() if doc.exists: data = doc.to_dict() sender_id = doc.id sender_name = data.get("display_name", "") or data.get("email", "") elif isinstance(sender_ref, str) and sender_ref.strip(): # String path like "users/abc123" doc = db.document(sender_ref).get() if doc.exists: data = doc.to_dict() sender_id = doc.id sender_name = data.get("display_name", "") or data.get("email", "") except Exception as e: print(f"[helpdesk] Error resolving sender: {e}") return sender_id, sender_name def _resolve_device_name(db, device_id: str) -> str: """Look up device_name from device_id.""" if not device_id: return "" try: doc = db.collection("devices").document(device_id.strip()).get() if doc.exists: return doc.to_dict().get("device_name", "") except Exception as e: print(f"[helpdesk] Error resolving device name: {e}") return "" def _doc_to_message(db, doc) -> HelpdeskMessage: """Convert a Firestore document snapshot to a HelpdeskMessage.""" data = doc.to_dict() # Resolve sender reference sender_ref = data.get("sender") sender_id, sender_name = _resolve_sender(db, sender_ref) # Handle date_sent (could be Firestore Timestamp) date_sent = data.get("date_sent", "") if isinstance(date_sent, datetime): date_sent = date_sent.strftime("%d %B %Y at %H:%M:%S UTC%z") # Resolve device name if device_id present device_id = data.get("device_id", "") device_name = "" if device_id: device_name = _resolve_device_name(db, device_id) # Handle acknowledged_at acknowledged_at = data.get("acknowledged_at", "") if isinstance(acknowledged_at, datetime): acknowledged_at = acknowledged_at.strftime("%d %B %Y at %H:%M:%S UTC%z") return HelpdeskMessage( id=doc.id, sender_id=sender_id, sender_name=sender_name, type=data.get("type", ""), date_sent=date_sent, subject=data.get("subject", ""), message=data.get("message", ""), phone=data.get("phone", ""), device_id=device_id, device_name=device_name, acknowledged=data.get("acknowledged", False), acknowledged_by=data.get("acknowledged_by", ""), acknowledged_at=acknowledged_at, ) def list_messages( user_id: str | None = None, device_id: str | None = None, msg_type: str | None = None, ) -> list[HelpdeskMessage]: """List helpdesk messages with optional filters.""" db = get_db() ref = db.collection(COLLECTION) query = ref if msg_type: query = query.where("type", "==", msg_type) if device_id: query = query.where("device_id", "==", device_id) docs = list(query.stream()) results = [] for doc in docs: msg = _doc_to_message(db, doc) # Filter by sender user_id client-side (sender is a DocumentReference) if user_id and msg.sender_id != user_id: continue results.append(msg) # Sort by date_sent descending results.sort(key=lambda m: m.date_sent or "", reverse=True) return results def get_message(message_id: str) -> HelpdeskMessage: """Get a single helpdesk message by ID.""" db = get_db() doc = db.collection(COLLECTION).document(message_id).get() if not doc.exists: raise NotFoundError("Helpdesk message") return _doc_to_message(db, doc) def toggle_acknowledged(message_id: str, acknowledged_by: str = "") -> HelpdeskMessage: """Toggle the acknowledged status of a helpdesk message.""" db = get_db() doc_ref = db.collection(COLLECTION).document(message_id) doc = doc_ref.get() if not doc.exists: raise NotFoundError("Helpdesk message") data = doc.to_dict() currently_acknowledged = data.get("acknowledged", False) now = datetime.now(timezone.utc).strftime("%d %B %Y at %H:%M:%S UTC") if currently_acknowledged: doc_ref.update({ "acknowledged": False, "acknowledged_by": "", "acknowledged_at": "", }) else: doc_ref.update({ "acknowledged": True, "acknowledged_by": acknowledged_by, "acknowledged_at": now, }) updated_doc = doc_ref.get() return _doc_to_message(db, updated_doc)