
    j                         d Z ddlmZ ddlmZ ddlmZmZmZm	Z	 ddl
mZ ddlmZ ddlmZ ddlmZmZmZmZ dd	lmZmZ  G d
 d      Zy)a  
Upcoming events service for Aimantis dashboard.

Generates chronological list of upcoming check-ins and check-outs
with optimized queries and proper prefetching.

ORM Optimization Strategy:
- NO select_related() for property/property_type because we only access booking fields
  (platform, length_of_stay, total_price, id, check_in_date, check_out_date)
- prefetch_related() is used for guests collection to avoid N+1 queries
- .only() explicitly selects minimal fields needed for event display
    )date)chain)DictAnyListOptional)Prefetch)Booking)Guest)DEFAULT_UPCOMING_EVENTS_LIMITMAX_UPCOMING_EVENTS_LIMITEVENT_TYPE_CHECK_INEVENT_TYPE_CHECK_OUT)	get_todaynormalize_channel_namec            
           e Zd ZdZ	 	 ddee   dee   fdZdeee	f   fdZ
dedee   fd	Zd
edefdZd
edededeee	f   fdZdeeee	f      fdZy)UpcomingEventsServicez
    Service for generating upcoming dashboard events.
    
    Properly prefetches main guests to avoid N+1 queries
    and normalizes channel names for display.
    Nstructure_idlimitc                 j    || _         t               | _        t        |xs t        t
              | _        y)z
        Initialize the upcoming events service.
        
        Args:
            structure_id: Optional structure ID for multi-tenant filtering
            limit: Maximum number of events to return (default: 5)
        N)r   r   todayminr   r   r   )selfr   r   s      6/backend/dashboard/services/upcoming_events_service.py__init__zUpcomingEventsService.__init__(   s*     )[
?"?AZ[
    returnc                 :    | j                   rd| j                   iS i S )z&Get structure filter dict for queries.r   )r   )r   s    r   _get_structure_filterz+UpcomingEventsService._get_structure_filter8   s     6:6G6G 1 12OROr   
start_datec                 0   t        dt        j                  j                  d      d      }t	        t        j                  j                  dd|i| j                         j                  |      j                  ddd	d
ddd      j                  d            S )a9  
        Fetch bookings with prefetched main guests.
        
        Uses Prefetch to only load the main guest for each booking,
        avoiding N+1 queries in the event generation loop.
        
        For check-in events:
        - Only include future check-ins (check_in_date >= today)
        - Exclude already checked-in bookings from today
        
        ORM Optimization:
        - NO select_related(): We only access booking.platform, booking.length_of_stay,
          booking.total_price, booking.id, booking.check_in_date, booking.check_out_date.
          We do NOT access booking.property or booking.property_type objects.
        - prefetch_related('guests'): Required because we iterate booking.main_guest_list
          to get guest names. Without prefetch, this would cause N+1 queries.
        - .only(): Selects only fields needed for event display to minimize data transfer.
        
        Args:
            start_date: Fetch bookings from this date onwards
            
        Returns:
            List of Booking objects with prefetched guests
        guestsT)is_main_guestmain_guest_list)querysetto_attrcheck_in_date__gteidcheck_in_datecheck_out_datelength_of_staytotal_priceplatformis_checked_in )
r	   r   objectsfilterlistr
   r   prefetch_relatedonlyorder_by)r   r    main_guest_prefetchs      r   _get_bookings_with_guestsz/UpcomingEventsService._get_bookings_with_guests<   s    2 ']])))=%
 OO"" #-,,.
 12T   Xo&!
 	
r   bookingc                 @    t        |dg       }|r|d   j                  S y)u  
        Extract main guest name from booking.
        
        Uses the prefetched main_guest_list attribute.
        
        Args:
            booking: Booking object
            
        Returns:
            Main guest full name or "—" if not found
        r$   r   u   —)getattr	full_name)r   r8   main_guestss      r   _get_main_guest_namez*UpcomingEventsService._get_main_guest_namep   s)     g'8"=q>+++r   
event_type
event_datec                     |j                   || j                  |      t        |j                        |j                  xs d|j
                  r|j
                  dnd|j                         dS )a  
        Build a single event dictionary.
        
        Args:
            booking: Booking object
            event_type: "check_in" or "check_out"
            event_date: Date of the event
            
        Returns:
            Event dictionary
        r   z.2fz0.00)
booking_idr>   
guest_namechannelnightsamountr   )r(   r=   r   r-   r+   r,   	isoformat)r   r8   r>   r?   s       r   _build_eventz"UpcomingEventsService._build_event   sf    $ "**$33G<-g.>.>?,,16=6I6I,,S1v((*
 	
r   c                    | j                  | j                        }|D cg c])  }|j                  | j                  k(  r|j                  s|+ }}|}t	        t        |D cg c]  }t        ||j                  f c}|D cg c]  }t        ||j                  f c}            }|j                  d        g }t               }|D ]  \  }}	}
|t        k(  r|	j                  |v r| j                  |	||
      }|j                  |       |t        k(  r|j                  |	j                         t        |      | j                   k\  s |S  |S c c}w c c}w c c}w )a  
        Get chronological list of upcoming events.
        
        Fetches check-ins and check-outs, combines them,
        sorts by date, and removes duplicates.
        
        Rules:
        - Only include FUTURE events
        - Exclude already checked-in bookings for today
        - Show check-in OR check-out (not both for same booking)
        
        Returns:
            List of event dictionaries, sorted chronologically
        c                     | d   S )N   r/   )xs    r   <lambda>z2UpcomingEventsService.get_events.<locals>.<lambda>   s    1Q4r   )key)r7   r   r)   r.   r2   r   r   r   r*   sortsetr(   rG   appendaddlenr   )r   all_bookingsbbookings_checkinbookings_checkoutcombined_eventseventsadded_booking_idsr>   r8   r?   events               r   
get_eventsz UpcomingEventsService.get_events   sv   " 55djjA
 $
#!OOtzz1aoo | 	 
 )  .- )!Q__=- /. *1a.>.>?.	
 	0 E/>+J11gjjDU6U%%gz:FEMM%  00!%%gjj1 6{djj(! 0?  [
s   .E E E)NN)__name__
__module____qualname____doc__r   intr   r   strr   r   r   r   r
   r7   r=   rG   r[   r/   r   r   r   r       s     '+#\sm\ }\ PtCH~ P2
D 2
T'] 2
hG  "

 
 	

 
c3h
6BDc3h0 Br   r   N)r_   datetimer   	itertoolsr   typingr   r   r   r   django.db.modelsr	   bookings.modelsr
   guests.modelsr   dashboard.constantsr   r   r   r   dashboard.services.utilsr   r   r   r/   r   r   <module>rj      s=      , , % #   G~ ~r   