
    {iI                         d Z ddlZddlZddlZddlmZ ddlmZmZm	Z	 ddl
mZ  G d de          Z G d d	          Z G d
 d          ZdS )z
Page Management System - Intelligent Page State and Pool Management

This module provides intelligent page management for handling multiple tabs
with state tracking, busy detection, and recovery mechanisms.
    N)Enum)OptionalDictList)Pagec                   *    e Zd ZdZdZdZdZdZdZdZ	dS )		PageStatezPage state enumeration.idlebusyerrorcrashedloadingstuckN)
__name__
__module____qualname____doc__IDLEBUSYERRORCRASHEDLOADINGSTUCK     8/home/byschii/byschiidev/penelope/lib/page_management.pyr	   r	      s2        !!DDEGGEEEr   r	   c                       e Zd ZdZdedefdZdefdZdefdZ	defdZ
defd	ZddedefdZddedee         fdZdefdZd ZdefdZd ZdefdZddedefdZd Zd ZdS )ManagedPagezK
    Wrapper for Playwright Page with state management and monitoring.
    pagepage_idc                 R   || _         || _        t          j        | _        d| _        d| _        d| _        t          j                    | _	        t          j                    | _        d| _        d| _        | j                             d           | j                             d           dS )z
        Initialize managed page.
        
        Args:
            page (Page): Playwright page instance
            page_id (str): Unique identifier for this page
        Nr   i`  )r   r    r	   r   statecurrent_operationoperation_start_timeerror_counttimelast_activityasyncioLocklocklast_known_mouse_xlast_known_mouse_yset_default_timeoutset_default_navigation_timeout)selfr   r    s      r   __init__zManagedPage.__init__!   s     	^
0459!!Y[[LNN	"#"# 		%%e,,,	0077777r   returnc                 ,    | j         t          j        k    S )z Check if page is currently busy.)r"   r	   r   r/   s    r   is_busyzManagedPage.is_busy9       zY^++r   c                 ,    | j         t          j        k    S )z.Check if page is available for new operations.)r"   r	   r   r3   s    r   is_availablezManagedPage.is_available=   r5   r   c                 6  K   	 | j         r| j        t          j        k    rdS | j                             d           d{V  dS # t
          $ rJ}t          d| j         d|            |                     t          j                   d{V  Y d}~dS d}~ww xY w)z
        Check if page is responsive and ready for operations.
        
        Returns:
            bool: True if page is responsive, False otherwise
        Fz() => document.readyStateNTu   ⚠️ Page z responsiveness check failed: )	r   r"   r	   r   evaluate	Exceptionprintr    
_set_state)r/   es     r   is_responsivezManagedPage.is_responsiveA   s      	9 
i.? ? ?u )$$%@AAAAAAAAA4 	 	 	PPPQPPQQQ//)"344444444455555	s   A  A 
B?BBc                    K   	 | j         r| j        t          j        k    rdS | j                             d           d{V }|                    dd          S # t          $ r Y dS w xY w)z#Check if page is currently loading.Fz
                () => {
                    return {
                        readyState: document.readyState,
                        loading: document.readyState !== 'complete'
                    }
                }
            Nr   )r   r"   r	   r   r9   getr:   )r/   loading_infos     r   
is_loadingzManagedPage.is_loadingU   s      	9 
i.? ? ?u!%!3!3 5 " "      L  ##Iu555 	 	 	55	s   A 5A 
A&%A&,  max_operation_timec                     | j         t          j        k    r(| j        r!t	          j                    | j        z
  }||k    S dS )a  
        Check if current operation has been running too long.
        
        Args:
            max_operation_time (int): Maximum operation time in seconds (default: 5 minutes)
            
        Returns:
            bool: True if operation appears stuck
        F)r"   r	   r   r$   r&   )r/   rD   operation_durations      r   is_stuckzManagedPage.is_stucki   s@     :''D,E'!%t/H!H%(:::ur   N	new_state	operationc                   K   | j         4 d{V  | j        }|| _        t          j                    | _        |t          j        k    r:|| _        t          j                    | _        t          d| j	         d|            n|t          j
        k    r7d| _        d| _        |t          j        k    rt          d| j	         d           nx|t          j        k    r9| xj        dz  c_        |rd| nd| _        t          d| j	         d|            n/|t          j        k    rd	| _        t          d| j	         d
           ddd          d{V  dS # 1 d{V swxY w Y   dS )zThread-safe state change.Nu
   📄 Page z is now BUSY with: z is now IDLE   zERROR: r   z is now in ERROR state: r   z is now CRASHED)r*   r"   r&   r'   r	   r   r#   r$   r;   r    r   r   r%   r   )r/   rH   rI   	old_states       r   r<   zManagedPage._set_statex   s/     9 	B 	B 	B 	B 	B 	B 	B 	B
I"DJ!%DIN**)2&,0IKK)O4<OOIOOPPPPin,,)-&,0)	..At|AAABBBio--  A%  BK)X)>9)>)>)>QX&T4<TTTTUUUUi///)2&@4<@@@AAA/	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	B 	Bs   D0E
E Ec                 V   K   |                      t          j        |           d{V  dS )z*Mark page as busy with specific operation.N)r<   r	   r   )r/   rI   s     r   set_busyzManagedPage.set_busy   s4      ooini88888888888r   c                 T   K   |                      t          j                   d{V  dS )z/Mark page as idle and ready for new operations.N)r<   r	   r   r3   s    r   set_idlezManagedPage.set_idle   s2      ooin-----------r   r   c                 V   K   |                      t          j        |           d{V  dS )zMark page as in error state.N)r<   r	   r   )r/   r   s     r   	set_errorzManagedPage.set_error   s4      ooiou55555555555r   c                 T   K   |                      t          j                   d{V  dS )zMark page as crashed.N)r<   r	   r   r3   s    r   set_crashedzManagedPage.set_crashed   s3      ooi/00000000000r   c                 &  K   	 | j         r&|                                  d{V r| j         j        nd}| j         r9|                                  d{V r| j                                          d{V nd}n#  d}d}Y nxY wd}| j        rt          j                    | j        z
  }| j        | j        j        | j	        ||                                  d{V | 
                                 d{V |                                 | j        | j        ||dS )z%Get detailed page status information.N)r    r"   r#   rF   
responsiver   r   r%   r'   urltitle)r   r>   rW   rX   r$   r&   r    r"   valuer#   rB   rG   r%   r'   )r/   current_urlcurrent_titlerF   s       r   
get_statuszManagedPage.get_status   sY     	!+/9]t?Q?Q?S?S9S9S9S9S9S9S]$)--Y]K7;yi4K]K]K_K_E_E_E_E_E_E_i$)//"3"33333333eiMM	!K MMM!$ 	I!%t/H!H |Z%!%!7"4 $ 2 2 4 4444444!__........]]__+!/"
 
 	
s   A1A6 6A>   timeoutc                    K   t          j                     }t          j                     |z
  |k     rJ|                                 rdS t          j        d           d{V  t          j                     |z
  |k     JdS )z
        Wait until page is ready for new operations.
        
        Args:
            timeout (int): Maximum time to wait in seconds
            
        Returns:
            bool: True if page became ready, False if timeout
        T      ?NF)r&   r7   r(   sleep)r/   r^   
start_times      r   wait_until_readyzManagedPage.wait_until_ready   s       Y[[
ikkJ&00  "" t-$$$$$$$$$ ikkJ&00
 ur   c                 X  K   t          d| j         d           | j        4 d{V  | j        }t          j        | _        d| _        d| _        t          j                    | _	        ddd          d{V  n# 1 d{V swxY w Y   t          d| j         d|j
         d           dS )z?Force page recovery by resetting state and clearing operations.u   🔧 Force recovering page z...Nu
   🔄 Page z recovered from z to IDLE)r;   r    r*   r"   r	   r   r#   r$   r&   r'   rY   )r/   rL   s     r   force_recoveryzManagedPage.force_recovery   s5     =DL===>>>9 	- 	- 	- 	- 	- 	- 	- 	-
I"DJ%)D"(,D%!%D	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	R4<RRRRRSSSSSs   ?A99
BBc                 ^    d| j          d| j        j         d| j        r| j        j        nd dS )Nz<ManagedPage id=z state=z url=zN/A>)r    r"   rY   r   rW   r3   s    r   __repr__zManagedPage.__repr__   s<    v$,vvtz7Gvv_c_hNsdimmnsvvvvr   )rC   N)r]   )r   r   r   r   r   strr0   boolr4   r7   r>   rB   intrG   r	   r   r<   rN   rP   rR   rT   dictr\   rc   re   rh   r   r   r   r   r      s        8T 8C 8 8 8 80, , , , ,,d , , , ,T    ($    ( 3     B B) B B B B B69 9 9 9 9. . .6S 6 6 6 61 1 1
$ 
 
 
 
6 c 4    &T T Tw w w w wr   r   c                       e Zd ZdZddefdZd Zd Zddefd	Zdde	e
         defdZdefdZddede	e         fdZde
de	e         fdZdde	e
         defdZd Zd ZdefdZd Zd
S )IntelligentPagePoolzj
    Intelligent page pool that manages multiple tabs with automatic recovery
    and load balancing.
       	max_pagesc                 n    || _         || _        i | _        d| _        t	          j                    | _        dS )z
        Initialize page pool.
        
        Args:
            browser_context: Playwright browser context
            initial_pages (int): Number of pages to create initially
            max_pages (int): Maximum number of pages allowed
        r   N)browser_contextrq   pagespage_counterr(   r)   	pool_lock)r/   rs   rq   s      r   r0   zIntelligentPagePool.__init__   s3      /"-/
 r   c                 h   K   | j                             d| j                   t          d           dS )z
        Setup browser context event listeners.
        
        Listens for:
        - New pages created (manual user tabs, popups, etc)
        - Auto-registers orphaned pages with generated IDs
        r   u)   📡 Browser context listeners configuredN)rs   on_on_page_createdr;   r3   s    r   setup_listenersz#IntelligentPagePool.setup_listeners   s9       	(=>>>9:::::r   c           	         t          fd| j                                        D                       rt          d           dS t	          t          j                    dz            }d                    t          j        dd                    }d	| d
| }t          d|            t          |          }|| j        |<   t          d| dt          | j                   d| j         d           |                     |           dS )ax  
        Handle new page created in browser context.
        
        This fires when:
        - User clicks + button to create new tab
        - User opens a popup (window.open)
        - Links open in new tab
        
        We auto-register these orphaned pages so the pool stays in sync.
        
        Args:
            page: The newly created Playwright page
        c              3   .   K   | ]}|j         k    V  d S ri   )r   ).0mpr   s     r   	<genexpr>z7IntelligentPagePool._on_page_created.<locals>.<genexpr>  s)      ==2rw$======r   u-   📄 Page already tracked, ignoring duplicateN   abcdef0123456789   )kauto__u:   🆕 Detected new page created by user, auto-registering: u   ✅ Orphaned page registered:  (/))anyrt   valuesr;   rl   r&   joinrandomchoicesr   lenrq   _attach_close_handler)r/   r   	timestamprandom_suffixauto_page_idmanaged_pages    `    r   ry   z$IntelligentPagePool._on_page_created  s$    ====):):)<)<===== 	BCCCF
 	d*++	/AQ G G GHH:y::=::Y<YYZZZ #466 $0
< b|bbs4:bbQUQ_bbbccc 	""<00000r   rK   initial_pagesc                    K   |                                   d{V  t          |          D ]}|                                  d{V  dS )z Initialize pages asynchronously.N)rz   range_create_page)r/   r   r   s      r   
initializezIntelligentPagePool.initialize)  sv       ""$$$$$$$$$ }%% 	& 	&A##%%%%%%%%%%	& 	&r   Ncustom_page_idr1   c           
      x  K   | j         4 d{V  |r|| j        v rt          d| d          |}nF| xj        dz  c_        d| j         }|| j        v r#| xj        dz  c_        d| j         }|| j        v #	 t	          | j                  | j        k    rt          d| j         d          |s?| j        dk    r4t          | j        d          r| j        j        r| j        j        d	         }n| j                                         d{V }t          ||          }|| j        |<   | 
                    |           t          d
| dt	          | j                   d| j         d           |cddd          d{V  S # t          $ r}t          d| d|             d}~ww xY w# 1 d{V swxY w Y   dS )zFCreate a new managed page, reusing the initial Firefox page if needed.NzPage with ID 'z' already existsrK   page_zMaximum page limit (z") reached. Cannot create new page.rt   r   u   📄 Created new page: r   r   r   u   ❌ Failed to create page : )rv   rt   r:   ru   r   rq   hasattrrs   new_pager   r   r;   )r/   r   r    playwright_pager   r=   s         r   r   z IntelligentPagePool._create_page2  s     > ,	 ,	 ,	 ,	 ,	 ,	 ,	 ,	 :!TZ//#$U^$U$U$UVVV(!!Q&!!5$"355 ++%%*%%9d&799G ++tz??dn44#$m4>$m$m$mnnn & L$*;q*@*@WTMacjEkEk*@pt  qE  qK*@&*&:&@&COO,0,@,I,I,K,K&K&K&K&K&K&KO  +?GDD&2
7# **<888^^^3tz??^^T^^^^___#Q,	 ,	 ,	 ,	 ,	 ,	 ,	 ,	 ,	 ,	 ,	 ,	 ,	 ,	T    A7AAaAABBBU,	 ,	 ,	 ,	 ,	 ,	 ,	 ,	 ,	 ,	 ,	 ,	 ,	 ,	 ,	 ,	s1   A(F)9C5F
F&F!!F&&F))
F36F3r   c                      j          fd}j                            d|           t          d            dS )a  
        Attach a close event listener to a page.
        
        When user closes the tab in browser (clicks X button), this handler:
        1. Removes page from pool immediately to prevent stale references
        2. Marks page as CRASHED for any lingering API references
        3. Logs the event for debugging
        
        Args:
            managed_page (ManagedPage): The managed page to attach listener to
        c                      t          d d           j        v rj        = t          d d           	 t          j         _        t          d d           dS #  Y dS xY w)z/Callback when page is closed by user in browseru
   🔴 Page z& was closed by user (browser X button)u   🗑️  Page z removed from poolu
   💥 Page z marked as CRASHEDN)r;   rt   r	   r   r"   )r   r    r/   s   r   on_closez;IntelligentPagePool._attach_close_handler.<locals>.on_closep  s    NwNNNOOO $*$$Jw'BwBBBCCC%.%6">7>>>?????s   $A   A%closeu+   📌 Close event listener attached to page N)r    r   rx   r;   )r/   r   r   r    s   `` @r   r   z)IntelligentPagePool._attach_close_handlerb  sj     &	 	 	 	 	 	 	$ 	Wh///EGEEFFFFFr   
   wait_timeoutc           	         K   t          j                     }dt          t          j                     dz            dz   }t          d| dt          | j                              t          j                     |z
  |k     rzd | j                                        D             }t          d| d|            | j                                        D ]4}|                                rt          d| d	|j                    |c S 5t          | j                  | j	        k     rwt          d| d
t          | j                   d| j	         d           	 | 
                                 d{V S # t          $ r}t          d| d|            Y d}~nd}~ww xY wt          d| dt          j                     |z
  dd           t          j        d           d{V  t          j                     |z
  |k     zt          d| d           dS )z6
        Get an available page from the pool.
        req_r   i'  u   🔍 [z-] Searching for available page... Pool size: c                 .    i | ]\  }}||j         j        S r   )r"   rY   )r}   pidr   s      r   
<dictcomp>z:IntelligentPagePool.get_available_page.<locals>.<dictcomp>  s#    UUUYS$3
 0UUUr   z] Current page states: u   📄 [z] Using available page: z] Creating new page (r   r   Nu   ⚠️ [z] Failed to create new page: u   ⏳ [z"] No pages available, waiting... (z.1fzs)r`   z#] No pages available within timeout)r&   rl   r;   r   rt   itemsr   r7   r    rq   r   r:   r(   ra   )r/   r   rb   
request_idpage_statesr   r=   s          r   get_available_pagez&IntelligentPagePool.get_available_page  sr      Y[[
=C	d 233e;==
azaaPSTXT^P_P_aabbbikkJ&55UU$*BRBRBTBTUUUKK:KKkKKLLL 
))++    $$&&  U:UUt|UUVVVKKK 
 4://czccDJccRVR`cccdddS!%!2!2!4!44444444  S S SQZQQaQQRRRRRRRRS h*hh	V`H`hhhhiii-$$$$$$$$$) ikkJ&55, 	HHHHIIIts   E/ /
F9FFr    c                 6    | j                             |          S )zGet specific page by ID.)rt   r@   r/   r    s     r   get_page_by_idz"IntelligentPagePool.get_page_by_id  s    z~~g&&&r   c                 >   K   |                      |           d{V S )ai  
        Create a new page with optional custom ID.
        
        Args:
            page_id (str, optional): Custom page ID. If None, auto-generated ID will be used.
            
        Returns:
            ManagedPage: The newly created managed page
            
        Raises:
            Exception: If page creation fails or page limit exceeded
        )r   N)r   r   s     r   create_pagezIntelligentPagePool.create_page  s1       &&g&>>>>>>>>>r   c                    K   | j                                         D ]G}|                                r1t          d|j                    |                                 d{V  HdS )z&Recover pages that appear to be stuck.u   🔧 Recovering stuck page: N)rt   r   rG   r;   r    re   )r/   r   s     r   recover_stuck_pagesz'IntelligentPagePool.recover_stuck_pages  s{      J%%'' 	, 	,D}} ,CT\CCDDD))+++++++++	, 	,r   c                    K   d | j                                         D             }|D ]O}t          d|            	 | j         |         j                                         d{V  n#  Y nxY w| j         |= PdS )z#Remove crashed pages from the pool.c                 B    g | ]\  }}|j         t          j        k    |S r   )r"   r	   r   )r}   r    r   s      r   
<listcomp>z=IntelligentPagePool.cleanup_crashed_pages.<locals>.<listcomp>  s6     
 
 
%zY... ...r   u   🗑️ Removing crashed page: N)rt   r   r;   r   r   )r/   crashed_pagesr    s      r   cleanup_crashed_pagesz)IntelligentPagePool.cleanup_crashed_pages  s      
 
)-)9)9););
 
 

 % 	$ 	$G=G==>>>j).446666666666
7##	$ 	$s   *A((A,c                 (  K   i }g }| j                                         D ]U}|                                 d{V }|                    |           |d         }|                    |d          dz   ||<   Vt          | j                   | j        ||dS )zGet comprehensive pool status.Nr"   r   rK   )total_pagesrq   status_by_statert   )rt   r   r\   appendr@   r   rq   )r/   r   page_statusesr   statusr"   s         r   get_pool_statusz#IntelligentPagePool.get_pool_status  s      J%%'' 	G 	GD??,,,,,,,,F  (((7OE%4%8%8%B%BQ%FOE"" tz??."	
 
 	
r   c                 r  K   t          d           | j                                        D ]c\  }}	 t          d|            |j                                         d{V  8# t
          $ r}t          d| d|            Y d}~\d}~ww xY w| j                                         t          d           dS )zClose all pages in the pool.u!   🔒 Closing all pages in pool...u   📄 Closing page: Nu   ⚠️ Error closing page r   u   ✅ All pages closed)r;   rt   r   r   r   r:   clear)r/   r    r   r=   s       r   close_all_pagesz#IntelligentPagePool.close_all_pages  s      1222!Z--// 	C 	CMGTC5G55666ioo'''''''''' C C CA7AAaAABBBBBBBBC 	
$%%%%%s   1A##
B-BB)rp   )rK   ri   )r   )r   r   r   r   rl   r0   rz   ry   r   r   rj   r   r   r   r   r   r   r   r   rm   r   r   r   r   r   ro   ro      s        
( (3 ( ( ( (
; 
; 
;$1 $1 $1L& &c & & & &. .# .+ . . . .`!G+ !G !G !G !GF S (;BW    B'c 'h{.C ' ' ' '? ?# ?+ ? ? ? ? , , ,$ $ $
t 
 
 
 
&& & & & &r   ro   )r   r&   r(   r   enumr   typingr   r   r   patchright.async_apir   r	   r   ro   r   r   r   <module>r      s             ' ' ' ' ' ' ' ' ' ' & & & & & &       Cw Cw Cw Cw Cw Cw Cw CwLM& M& M& M& M& M& M& M& M& M&r   