"""Unified decision service - shared between CLI and HTTP API. This module provides the core business logic for listing decision operations (like/dislike). Both the CLI and HTTP API should use these functions. """ from models.decision import ListingDecision from repositories.decision_repository import DecisionRepository VALID_DECISIONS = {"liked", "disliked", "seen"} VALID_LISTING_TYPES = {"RENT", "BUY"} def set_decision( repository: DecisionRepository, user_id: int, listing_id: int, listing_type: str, decision: str, price_at_decision: float | None = None, ) -> ListingDecision: """Set or update a decision for a listing. price_at_decision is only meaningful for decision="seen"; it lets the client resurface a listing whose price has changed since dismissal. """ if decision not in VALID_DECISIONS: raise ValueError( f"Invalid decision: {decision}. Must be one of {VALID_DECISIONS}" ) if listing_type not in VALID_LISTING_TYPES: raise ValueError( f"Invalid listing_type: {listing_type}. Must be one of {VALID_LISTING_TYPES}" ) # Only carry the price column when the decision is "seen" — liked/disliked # decisions ignore it. This keeps the column null for those rows. price = price_at_decision if decision == "seen" else None return repository.upsert_decision( user_id, listing_id, listing_type, decision, price ) def get_user_decisions( repository: DecisionRepository, user_id: int, ) -> list[ListingDecision]: """Get all decisions for a user.""" return repository.get_decisions_for_user(user_id) def remove_decision( repository: DecisionRepository, user_id: int, listing_id: int, listing_type: str, ) -> bool: """Remove a decision (un-like/un-dislike). Returns False if not found.""" if listing_type not in VALID_LISTING_TYPES: raise ValueError( f"Invalid listing_type: {listing_type}. Must be one of {VALID_LISTING_TYPES}" ) return repository.delete_decision(user_id, listing_id, listing_type) def get_disliked_ids( repository: DecisionRepository, user_id: int, listing_type: str, ) -> set[int]: """Get all disliked listing IDs for a user and listing type.""" return repository.get_disliked_listing_ids(user_id, listing_type) def get_liked_ids( repository: DecisionRepository, user_id: int, listing_type: str, ) -> set[int]: """Get all liked listing IDs for a user and listing type.""" return repository.get_liked_listing_ids(user_id, listing_type)