
    j                         d Z ddlmZmZ ddl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 ddlmZmZ dd	lmZmZmZmZ  G d
 d      Zy)z
Occupancy service for Aimantis dashboard.

Calculates occupancy percentages for:
- Today
- Next 7 days
- Next 30 days

Uses optimized SQL aggregation to avoid Python loops.
    )date	timedelta)DictAnyOptional)Q)timezone)Booking)Property)OCCUPANCY_WINDOWSOCCUPANCY_ROUNDING)calculate_overlapping_nights	get_todaysafe_divideround_occupancyc                       e Zd ZdZddee   fdZdeee	f   fdZ
defdZded	edefd
ZdefdZdefdZdefdZdeeef   fdZy)OccupancyServicez
    Service for calculating occupancy percentages.
    
    Uses efficient overlap calculations and avoids N+1 queries
    by batching all bookings for a given window.
    Nstructure_idc                 0    || _         t               | _        y)z
        Initialize the occupancy service.
        
        Args:
            structure_id: Optional structure ID for multi-tenant filtering
        N)r   r   today)selfr   s     0/backend/dashboard/services/occupancy_service.py__init__zOccupancyService.__init__&   s     )[
    returnc                 :    | j                   rd| j                   iS i S )z&Get structure filter dict for queries.r   r   r   s    r   _get_structure_filterz&OccupancyService._get_structure_filter0   s     6:6G6G 1 12OROr   c                     t         j                  j                         }| j                  r|j	                  | j                        }|j                         S )z'Get total room count for the structure.r   )r   objectsallr   filtercount)r   qss     r   _get_total_roomsz!OccupancyService._get_total_rooms4   sA    !!#(9(9:Bxxzr   window_start
window_endc                 >   | j                         }|dk(  ry||z
  j                  }||z  }|dk(  ryt        j                  j                  d||d| j                         j                  ddd      }t               }|D ]f  }t        |j                  |      }	t        |j                  |      }
|	|
k  s5|j                  |	|j                  f       |	t        d      z  }	|	|
k  r2h t        |      }t!        |dz  |d	
      }t        |d      }t#        |t$              S )a  
        Calculate occupancy percentage for a date window.
        
        CRITICAL BUSINESS RULE:
        - Counts DISTINCT occupied properties per day (not booking rows)
        - Occupancy can NEVER exceed 100%
        - Multiple bookings for the same room on the same day = 1 occupied room
        
        Algorithm:
        1. For each day in window, count DISTINCT property_ids with active bookings
        2. Sum daily occupied rooms across all days
        3. Divide by (total_rooms * window_days)
        
        Args:
            window_start: Start date (inclusive)
            window_end: End date (exclusive)
            
        Returns:
            Occupancy percentage (0-100), capped at 100
        r   )check_in_date__ltcheck_out_date__gtproperty_idcheck_in_datecheck_out_date   daysd   g        )default )r&   r1   r
   r!   r#   r   onlysetmaxr-   minr.   addr,   r   lenr   r   r   )r   r'   r(   total_roomswindow_daystotal_possible_nightsbookingsoccupied_room_nightsbookingcurrent_datebooking_endtotal_reserved_nights	occupancyoccupancy_cappeds                 r   _calculate_occupancy_for_windowz0OccupancyService._calculate_occupancy_for_window;   sI   2 ++-! "L066 +k 9 A% ??)) 
(+
 ((*
 $
	 	  #uGw44lCLg44jAK,$((,8K8K)LM	q 11 ,   !$$8 9  !C'!
	 y#./1CDDr   c                 h    | j                  | j                  | j                  t        d      z         S )zu
        Calculate occupancy for today.
        
        Returns:
            Occupancy percentage for today
        r/   r0   rF   r   r   r   s    r   get_today_occupancyz$OccupancyService.get_today_occupancy   /     33JJJJ**
 	
r   c                 h    | j                  | j                  | j                  t        d      z         S )z
        Calculate occupancy forecast for next 7 days.
        
        Returns:
            Average occupancy percentage for next 7 days
           r0   rH   r   s    r   get_next_7_days_occupancyz*OccupancyService.get_next_7_days_occupancy   rJ   r   c                 h    | j                  | j                  | j                  t        d      z         S )z
        Calculate occupancy forecast for next 30 days.
        
        Returns:
            Average occupancy percentage for next 30 days
           r0   rH   r   s    r   get_next_30_days_occupancyz+OccupancyService.get_next_30_days_occupancy   s/     33JJJJ++
 	
r   c                 b    | j                         | j                         | j                         dS )z
        Get all occupancy metrics in a single call.
        
        Returns:
            Dict with occupancy percentages for different time windows
        )r   next_7_daysnext_30_days)rI   rM   rP   r   s    r   get_occupancyzOccupancyService.get_occupancy   s2     --/99; ;;=
 	
r   )N)__name__
__module____qualname____doc__r   intr   r   strr   r   r&   r   rF   rI   rM   rP   rT   r4   r   r   r   r      s    !Xc] !PtCH~ P# RERE RE 
	REh

S 



3 



C 


tCH~ 
r   r   N)rX   datetimer   r   typingr   r   r   django.db.modelsr   django.utilsr	   bookings.modelsr
   properties.modelsr   dashboard.constantsr   r   dashboard.services.utilsr   r   r   r   r   r4   r   r   <module>rc      s:   	 % & &  ! # & E `
 `
r   