Ë
    7§Kj#M  ã                  ót   — d Z ddlmZ ddlZddlZddlZddlmZ ddlmZ dZ	dZ
dZd	Zd
ZdZdZ G d„ d«      Zy)u  Facebook groups table: import, discovery funnel, stats tracking.

Groups flow through a three-state funnel:
  untested â†’ proven (has queries) or dead (>=N scans, 0 queries)

Selection uses three tiers:
  ~50% proven (exploit), ~35% untested (screen), ~15% retest (probe dead).
é    )ÚannotationsN)Údatetime)ÚPathé
   é   é2   )Ú
czesci_tirÚczesci_inneÚfelgi_oponyÚmechanika_poradyg      à?gffffffÖ?g333333Ã?c                  óÒ   — e Zd ZdZdd„Zdd„Zdd„Zef	 	 	 	 	 dd„Zdd„Z	ddd„Z
	 d	 	 	 	 	 dd	„Zdd
„Zdd„Zdd„Zdd„Zefd d„Z	 d!	 	 	 	 	 	 	 	 	 d"d„Zd#d„Zdd$d„Zd%d„Zdd„Zy)&ÚGroupManagerz?Manages the fb_groups table and discovery funnel in catalog.db.c                óâ   — t        |«      j                  j                  dd¬«       t        j                  |«      | _        t        j                  | j
                  _        | j                  «        y )NT)ÚparentsÚexist_ok)	r   ÚparentÚmkdirÚsqlite3ÚconnectÚconnÚRowÚrow_factoryÚ_init_schema)ÚselfÚdb_paths     úH/var/www/html/agent.samochodowy/src/agent_samochodowy/ingestor/groups.pyÚ__init__zGroupManager.__init__(   sK   € ÜˆW‹×Ñ×"Ñ"¨4¸$Ð"Ô?Ü—O‘O GÓ,ˆŒ	Ü '§¡ˆ�	‰	ÔØ×ÑÕó    c                óÎ  — | j                   j                  d«       | j                   j                  d«       | j                   j                  d«       dD ]'  \  }}	 | j                   j                  d|› d|› �«       Œ) 	 | j                   j                  d«       | j                   j	                  «        y # t        j                  $ r Y Œvw xY w# t        j                  $ r Y ŒIw xY w)Na  
            CREATE TABLE IF NOT EXISTS fb_groups (
                group_id TEXT PRIMARY KEY,
                nazwa TEXT NOT NULL,
                url TEXT NOT NULL,
                kategoria TEXT NOT NULL DEFAULT '',
                aktywna INTEGER NOT NULL DEFAULT 0,
                last_scraped_at TEXT,
                last_hit_at TEXT,
                scans_count INTEGER NOT NULL DEFAULT 0,
                hits_count INTEGER NOT NULL DEFAULT 0,
                queries_count INTEGER NOT NULL DEFAULT 0
            )
        av  
            CREATE TABLE IF NOT EXISTS group_scan_log (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                group_id TEXT NOT NULL,
                scanned_at TEXT NOT NULL,
                queries INTEGER NOT NULL DEFAULT 0,
                hits INTEGER NOT NULL DEFAULT 0,
                posts_returned INTEGER NOT NULL DEFAULT 0
            )
        zICREATE INDEX IF NOT EXISTS idx_scan_log_group ON group_scan_log(group_id)))Úlast_hit_atÚTEXT)Úscans_countúINTEGER NOT NULL DEFAULT 0)Ú
hits_countr#   )Úqueries_countr#   )Úgroup_statez TEXT NOT NULL DEFAULT 'untested'z!ALTER TABLE fb_groups ADD COLUMN ú zOALTER TABLE group_scan_log ADD COLUMN posts_returned INTEGER NOT NULL DEFAULT 0)r   Úexecuter   ÚOperationalErrorÚcommit)r   ÚcolÚdefns      r   r   zGroupManager._init_schema2   sâ   € Ø�	‰	×Ñð ô 	ð 	�	‰	×Ñð 	ô 		ð 	�	‰	×ÑØWô	
ð
ò 
	‰IˆC�ðØ—	‘	×!Ñ!Ð$EÀcÀUÈ!ÈDÈ6Ð"RÕSð
	ð	Ø�I‰I×ÑØaôð
 	�	‰	×ÑÕøô ×+Ñ+ò Ùðûô ×'Ñ'ò 	Ùð	ús$   Á!B5Á?C Â5CÃ
CÃC$Ã#C$c                óÞ  — d}t        |dd¬«      5 }t        j                  |«      }|D ]’  }| j                  j	                  d|d   j                  «       |d   j                  «       |d   j                  «       |j                  d	d«      j                  «       t        |j                  d
d«      «      f«       |dz  }Œ” 	 ddd«       | j                  j                  «        |S # 1 sw Y   Œ%xY w)z7UPSERT groups from CSV. Returns count of rows imported.r   Ú zutf-8)ÚnewlineÚencodingaˆ  
                    INSERT INTO fb_groups (group_id, nazwa, url, kategoria, aktywna)
                    VALUES (?, ?, ?, ?, ?)
                    ON CONFLICT(group_id) DO UPDATE SET
                        nazwa=excluded.nazwa,
                        url=excluded.url,
                        kategoria=excluded.kategoria,
                        aktywna=excluded.aktywna
                Úgroup_idÚnazwaÚurlÚ	kategoriaÚaktywnaé   N)	ÚopenÚcsvÚ
DictReaderr   r(   ÚstripÚgetÚintr*   )r   Úcsv_pathÚcountÚfÚreaderÚrows         r   Ú
import_csvzGroupManager.import_csvh   sá   € àˆÜ�( B°Ô9ð 	¸QÜ—^‘^ AÓ&ˆFØò �Ø—	‘	×!Ñ!ð #ð ˜
‘O×)Ñ)Ó+Ø˜‘L×&Ñ&Ó(Ø˜‘J×$Ñ$Ó&Ø—G‘G˜K¨Ó,×2Ñ2Ó4Ü˜Ÿ™ 	¨1Ó-Ó.ðôð ˜‘
‘ñ!÷	ð& 	�	‰	×ÑÔØˆ÷)	ð 	ús   ‘B-C#Ã#C,c                óÖ   — | j                   j                  d||f«      }|j                  «       }|syt        |«      }t	        d„ |D «       «      }t	        d„ |D «       «      }||z  }|||fS )zBReturn (scans_in_window, queries_in_window, hit_rate) for a group.z–
            SELECT hits, queries FROM group_scan_log
            WHERE group_id = ?
            ORDER BY scanned_at DESC
            LIMIT ?
        )r   r   g        c              3  ó&   K  — | ]	  }|d    –— Œ y­w)ÚqueriesN© ©Ú.0Úrs     r   ú	<genexpr>z-GroupManager._window_stats.<locals>.<genexpr>“   s   è ø€ Ò7¨Q˜A˜i�LÑ7ùó   ‚c              3  ó&   K  — | ]	  }|d    –— Œ y­w)ÚhitsNrF   rG   s     r   rJ   z-GroupManager._window_stats.<locals>.<genexpr>”   s   è ø€ Ò1 q˜˜6�Ñ1ùrK   )r   r(   ÚfetchallÚlenÚsum)	r   r1   ÚwindowÚcurÚrowsÚscansÚtotal_queriesÚ
total_hitsÚhit_rates	            r   Ú_window_statszGroupManager._window_stats…   sz   € ð �i‰i×Ñð !ð
 ˜Ðó!ˆð �|‰|‹~ˆÙØÜ�D“	ˆÜÑ7°$Ô7Ó7ˆÜÑ1¨DÔ1Ó1ˆ
Ø Ñ%ˆØ�m XÐ-Ð-r   c                óN   — | j                  |«      \  }}}|dkD  ry|t        k\  ryy)z<Compute group_state from scan history in the rolling window.r   ÚprovenÚdeadÚuntested)rX   ÚDEAD_SCAN_THRESHOLD)r   r1   rT   rE   Ú_s        r   Ú_compute_statezGroupManager._compute_state˜   s2   € à ×.Ñ.¨xÓ8Ñˆˆw˜Ø�QŠ;ØØÔ'Ò'ØØr   Nc                ó  — t        |xs t        «      }dj                  d„ |D «       «      }| j                  j	                  d|› d�|«      }dddddœ}|j                  «       D �]  }|d   }|d   }| j                  |«      }	||	xx   d	z  cc<   g }
g }|	|k7  r"|
j                  d
«       |j                  |	«       |	dk(  r*|d   d	k7  r"|
j                  d«       |j                  d	«       |	dk(  r7|d   dk7  r/|
j                  d«       |j                  d«       |dxx   d	z  cc<   |
sŒÅ|j                  |«       | j                  j	                  ddj                  |
«      › d�|«       �Œ | j                  j                  «        |S )u	  Recompute group_state for all groups in eligible categories.

        - proven â†’ aktywna=1
        - dead   â†’ aktywna=0  (removed from rotation, kept in DB)
        - untested â†’ aktywna unchanged

        Returns {state: count, "culled_this_run": N}.
        ú,c              3  ó    K  — | ]  }d –— Œ y­w©ú?NrF   ©rH   r^   s     r   rJ   z)GroupManager.auto_cull.<locals>.<genexpr>«   ó   è ø€ Ò2¨¤Ñ2ùó   ‚zb
            SELECT group_id, group_state, aktywna FROM fb_groups
            WHERE kategoria IN (ú
)
        r   )r\   rZ   r[   Úculled_this_runr1   r&   r6   zgroup_state = ?rZ   r5   zaktywna = ?r[   ri   zUPDATE fb_groups SET z, z WHERE group_id = ?)	ÚlistÚELIGIBLE_CATEGORIESÚjoinr   r(   rN   r_   Úappendr*   )r   Ú
categoriesÚcatsÚplaceholdersrR   ÚcountsrA   ÚgidÚ	old_stateÚ	new_stateÚsetsÚvalss               r   Ú	auto_cullzGroupManager.auto_cull¡   s�  € ô �JÒ5Ô"5Ó6ˆØ—x‘xÑ2¨TÔ2Ó2ˆØ�i‰i×Ñð %!à!- ð /	ð!ð óˆð
 /0¸1ÀaÐ\]Ñ!^ˆà—<‘<“>ó 	ˆCØ�j‘/ˆCØ˜MÑ*ˆIØ×+Ñ+¨CÓ0ˆIØ�9Ó Ñ"Óà ˆDØ!#ˆDà˜IÒ%Ø—‘Ð-Ô.Ø—‘˜IÔ&Ø˜HÒ$¨¨Y©¸1Ò)<Ø—‘˜MÔ*Ø—‘˜A”Ø˜FÒ" s¨9¡~¸Ò':Ø—‘˜MÔ*Ø—‘˜A”ØÐ(Ó)¨QÑ.Ó)âØ—‘˜CÔ Ø—	‘	×!Ñ!Ø+¨D¯I©I°d«OÐ+<Ð<OÐPØöð-	ð6 	�	‰	×ÑÔØˆr   c                ó,  — | j                  |«      }| j                  d|«      }| j                  d|«      }| j                  d|«      }||z   |z   }|sg S t        |«      |k  r|S d|t        fd|t        fd|t
        fg}|D �	�
�cg c]  \  }	}
}|
sŒ
|	|
|f‘Œ }}
}	}|||dœ}|t        |«      k  r,t        |«      D ��	�ci c]  \  }\  }	}}|	||k  rdnd“Œ }}	}}n«|t        |«      z
  }t        d„ |D «       «      xs d	}i }|D ]  \  }	}}t        ||z  |z  «      }d|z   ||	<   Œ! |t        |j                  «       «      z
  }|D ]@  \  }	}}|dk(  r n5|dkD  r||	xx   dz  cc<   |dz  }Œ&||	   dkD  sŒ/||	xx   dz  cc<   |dz  }ŒB dD ]  }	|j                  |	d«       Œ d}t        |«      D ])  }t        ||   «      }||   |kD  sŒ|||   |z
  z  }|||<   Œ+ d
D ];  }|dk  r n4t        ||   «      ||   z
  }t        ||«      }||xx   |z  cc<   ||z  }Œ= g }|r?|d   dkD  r7|j                  d„ ¬«       |j                  | j                  ||d   «      «       |r2|d   dkD  r*|j                  d„ ¬«       |j                  |d|d    «       |r2|d   dkD  r*|j                  d„ ¬«       |j                  |d|d    «       t!        «       }g }|D ]/  }|d   |vsŒ|j#                  |d   «       |j%                  |«       Œ1 |d| S c c}}
}	w c c}}	}w )uH  Pick n groups using three-tier discovery funnel.

        Tiers:
        - ~50% proven  (exploit â€” weighted by hit_rate)
        - ~35% untested (screen â€” oldest-first from eligible categories)
        - ~15% retest   (probe dead groups for revival)

        Empty-tier slots spill to tiers with remaining capacity.
        rZ   r\   r[   Úretest)rZ   r\   ry   r6   r   c              3  ó(   K  — | ]
  \  }}}|–— Œ y ­w©NrF   )rH   r^   rI   s      r   rJ   z+GroupManager.pick_groups.<locals>.<genexpr>ý   s   è ø€ Ò7¡' ! Q¨œAÑ7ùs   ‚g      ð?)r\   rZ   ry   c                ó    — | d    | d   xs dfS )NrW   Úlast_scraped_atr.   rF   ©Úgs    r   ú<lambda>z*GroupManager.pick_groups.<locals>.<lambda>%  s   € ¨¨*© ~°qÐ9JÑ7KÒ7QÈrÐ&R€ r   ©Úkeyc                ó"   — | d   d u| d   xs dfS ©Nr}   r.   rF   r~   s    r   r€   z*GroupManager.pick_groups.<locals>.<lambda>+  s%   € ØÐ'Ñ(°Ð4ØÐ'Ñ(Ò.¨Bð€ r   Nc                ó   — | d   xs dS r„   rF   r~   s    r   r€   z*GroupManager.pick_groups.<locals>.<lambda>4  s   €  QÐ'8Ñ%9Ò%?¸R€ r   r1   )Ú_resolve_categoriesÚ_get_groups_by_staterO   ÚTIER_PROVENÚTIER_UNTESTEDÚTIER_RETESTÚ	enumeraterP   ÚroundÚvaluesÚ
setdefaultrj   ÚminÚsortÚextendÚ_weighted_sampleÚsetÚaddrm   )r   Únr4   ro   rZ   r\   r[   Úall_availableÚtiersÚnameÚpoolÚratioÚ	non_emptyÚpoolsÚir^   ÚslotsÚ	remainingÚ	ratio_sumÚextraÚdiffÚoverflowÚtierÚavailÚspareÚtakeÚpickedÚseenÚresultr   s                                 r   Úpick_groupszGroupManager.pick_groupsÕ   sÚ  € ð ×'Ñ'¨	Ó2ˆà×*Ñ*¨8°TÓ:ˆØ×,Ñ,¨Z¸Ó>ˆØ×(Ñ(¨°Ó6ˆà Ñ)¨DÑ0ˆÙØˆIÜˆ}Ó Ò"Ø Ð ð
 �vœ{Ð+Ø˜¤=Ð1Ø�tœ[Ð)ð
ˆð
 CH×PÐPÑ->¨T°4¸Ê4�d˜D %Ò(ÐPˆ	ÒPØ!¨xÀ4ÑHˆà”�I“Òô -6°iÓ,@÷Bð BÙ(˜™L˜T 1 að   A¢™1¨1Ñ,ð BˆEó Bð œC 	›NÑ*ˆIÜÑ7¨YÔ7Ó7Ò>¸3ˆIØˆEØ"+ò (‘��a˜Ü˜i¨%Ñ/°)Ñ;Ó<�Ø %™i��d’ð(ð ”s˜5Ÿ<™<›>Ó*Ñ*ˆDØ'ò ‘
��a˜Ø˜1’9ÙØ˜!’8Ø˜$“K 1Ñ$“KØ˜A‘I‘DØ˜4‘[ 1“_Ø˜$“K 1Ñ$“KØ˜A‘I‘Dðð 5ò 	&ˆDØ×Ñ˜T 1Õ%ð	&ð ˆÜ˜“Kò 	$ˆDÜ˜˜d™Ó$ˆEØ�T‰{˜UÓ"Ø˜E $™K¨%Ñ/Ñ/�Ø#��d’ð		$ð
 5ò 	ˆDØ˜1Š}ÙÜ˜˜d™Ó$ u¨T¡{Ñ2ˆEÜ�x Ó'ˆDØ�$‹K˜4Ñ‹KØ˜Ñ‰Hð	ð  ˆñ �e˜H‘o¨Ò)Ø�K‰KÑRˆKÔSØ�M‰M˜$×/Ñ/°¸¸h¹ÓHÔIñ ˜˜jÑ)¨AÒ-Ø�M‰Mñð ô ð �M‰M˜(Ð#6 U¨:Ñ%6Ð7Ô8ñ �E˜(‘O aÒ'Ø�I‰IÑ@ˆIÔAØ�M‰M˜$Ð0  x¡Ð1Ô2ô ‹uˆØˆØò 	!ˆAØ�‰} DÒ(Ø—‘˜˜:™Ô'Ø—‘˜aÕ ð	!ð �b�qˆzÐùôU Qùô
Bs   ÂLÂLÂ>Lc                ó`   — |€t        t        «      S t        |t        «      r|gS t        |«      S r{   )rj   rk   Ú
isinstanceÚstr)r   r4   s     r   r†   z GroupManager._resolve_categoriesD  s0   € ØÐÜÔ+Ó,Ð,Ü�i¤Ô%Ø�;ÐÜ�I‹Ðr   c                ó�  — dj                  d„ |D «       «      }|dv r%| j                  j                  d|› d�g |¢|‘«      }n*| j                  j                  d|› d�g |¢|‘t        ‘«      }g }|j	                  «       D ]E  }t        |«      }| j                  |d   «      \  }}	}
|
|d<   ||d	<   |	|d
<   |j                  |«       ŒG |S )zñFetch groups by state from given categories, enriched with window stats.

        For proven/untested: only active groups (aktywna=1).
        For dead (retest): excludes hard-dead groups (>=HARD_DEAD_SCANS with 0 lifetime queries).
        ra   c              3  ó    K  — | ]  }d –— Œ y­wrc   rF   re   s     r   rJ   z4GroupManager._get_groups_by_state.<locals>.<genexpr>Q  s   è ø€ Ò8¨¤Ñ8ùrg   )rZ   r\   a  
                SELECT group_id, nazwa, url, kategoria, aktywna,
                       last_scraped_at, last_hit_at,
                       scans_count, hits_count, queries_count, group_state
                FROM fb_groups
                WHERE kategoria IN (zV)
                  AND group_state = ?
                  AND aktywna = 1
            zw)
                  AND group_state = ?
                  AND NOT (scans_count >= ? AND queries_count = 0)
            r1   rW   Úscans_in_windowÚqueries_in_window)rl   r   r(   ÚHARD_DEAD_SCANSrN   ÚdictrX   rm   )r   Ústatern   rp   rR   ÚgroupsrA   r   rT   rE   rW   s              r   r‡   z!GroupManager._get_groups_by_stateK  s  € ð —x‘xÑ8¨ZÔ8Ó8ˆàÐ*Ñ*Ø—)‘)×#Ñ#ð )%ð
 &2 Nð 3ð%ð &�:Ð%˜uÐ%ó'‰Cð —)‘)×#Ñ#ð )%ð
 &2 Nð 3ð%ð 7�:Ð6˜uÐ6¤oÐ6ó8ˆCð ˆØ—<‘<“>ò 	ˆCÜ�S“	ˆAØ'+×'9Ñ'9¸!¸J¹-Ó'HÑ$ˆE�7˜HØ$ˆAˆj‰MØ#(ˆAÐÑ Ø%,ˆAÐ!Ñ"Ø�M‰M˜!Õð	ð ˆr   c                óP  — t        |t        «      r|g}dj                  d„ |D «       «      }| j                  j	                  d|› d�|«      }g }|j                  «       D ]E  }t        |«      }| j                  |d   «      \  }}}	|	|d<   ||d<   ||d<   |j                  |«       ŒG |S )	z>Fetch all active groups with rolling hit_rate (legacy compat).ra   c              3  ó    K  — | ]  }d –— Œ y­wrc   rF   re   s     r   rJ   z2GroupManager._get_active_groups.<locals>.<genexpr>w  s   è ø€ Ò7¨¤Ñ7ùrg   úñ
            SELECT group_id, nazwa, url, kategoria, aktywna,
                   last_scraped_at, last_hit_at,
                   scans_count, hits_count, queries_count, group_state
            FROM fb_groups
            WHERE kategoria IN (z) AND aktywna = 1
        r1   rW   r±   r²   )	r­   r®   rl   r   r(   rN   r´   rX   rm   )
r   r4   rp   rR   r¶   rA   r   rT   rE   rW   s
             r   Ú_get_active_groupszGroupManager._get_active_groupss  sÈ   € ä�i¤Ô%Ø"˜ˆIØ—x‘xÑ7¨YÔ7Ó7ˆØ�i‰i×Ñð %!ð
 ". ð /	ð!ð óˆð ˆØ—<‘<“>ò 	ˆCÜ�S“	ˆAØ'+×'9Ñ'9¸!¸J¹-Ó'HÑ$ˆE�7˜HØ$ˆAˆj‰MØ#(ˆAÐÑ Ø%,ˆAÐ!Ñ"Ø�M‰M˜!Õð	ð ˆr   c                ó¤  — |D �cg c]
  }|d   dz   ‘Œ }}t        |t        |«      «      }g }t        t        t        |«      «      «      }t        |«      }t        |«      D ]h  }|s |S t	        j
                  ||d¬«      \  }	|j                  ||	   «       |j                  |	«      }
|j                  |
«       |j                  |
«       Œj |S c c}w )u:   Weighted random sample: higher hit_rate â†’ higher chance.rW   gš™™™™™©?r6   )ÚweightsÚk)	r�   rO   rj   ÚrangeÚrandomÚchoicesrm   ÚindexÚpop)r   r¶   r•   r   r¼   r¨   Ú	availableÚavailable_weightsr^   ÚidxÚposs              r   r’   zGroupManager._weighted_sample‰  sË   € à17Ö8¨A�1�Z‘= 4Ó'Ð8ˆÐ8Ü�”3�v“;ÓˆØˆÜœœs 6›{Ó+Ó,ˆ	Ü  ›MÐÜ�q“ò 	'ˆAÙØð ˆô —N‘N 9Ð6GÈ1ÔM‰EˆSØ�M‰M˜& ™+Ô&Ø—/‘/ #Ó&ˆCØ�M‰M˜#ÔØ×!Ñ! #Õ&ð	'ð ˆùò 9s   …Cc                ó2   — | j                  ||«      \  }}}|S )z*Compute hit_rate from last `window` scans.)rX   )r   r1   rQ   r^   rW   s        r   Ú_rolling_hit_ratezGroupManager._rolling_hit_rateš  s   € à×+Ñ+¨H°fÓ=‰ˆˆ1ˆhØˆr   c                óD  — t        j                  «       j                  «       }| j                  j	                  d|||||f«       | j                  j	                  d||||f«       |dkD  r| j                  j	                  d||f«       | j                  j                  «        y)z.Record scan results and update group counters.z‰
            INSERT INTO group_scan_log (group_id, scanned_at, queries, hits, posts_returned)
            VALUES (?, ?, ?, ?, ?)
        zü
            UPDATE fb_groups SET
                last_scraped_at = ?,
                scans_count = scans_count + 1,
                hits_count = hits_count + ?,
                queries_count = queries_count + ?
            WHERE group_id = ?
        r   z7UPDATE fb_groups SET last_hit_at = ? WHERE group_id = ?N)r   ÚnowÚ	isoformatr   r(   r*   )r   r1   rE   rM   Úposts_returnedrÊ   s         r   Úrecord_scanzGroupManager.record_scan£  sŸ   € ô �l‰l‹n×&Ñ&Ó(ˆð 	�	‰	×Ñð ð ˜˜W d¨NÐ;ô	=ð 	�	‰	×Ñð ð �4˜ (Ð+ô	-ð �!Š8Ø�I‰I×ÑØIØ�h�ôð
 	�	‰	×ÑÕr   c                ó,   — | j                  |dd¬«       y)zHLegacy: update last_scraped_at only (use record_scan for full tracking).r   )rE   rM   N)rÍ   )r   r1   s     r   Úmark_scrapedzGroupManager.mark_scrapedÁ  s   € à×Ñ˜¨1°1ÐÕ5r   c                ó„  ‡— | j                  |«      }dj                  d„ |D «       «      }| j                  j                  d|› d�|«      }ddddœŠg }|j	                  «       D ]E  }t        |«      }| j                  |d	   «      \  }}	}
|
|d
<   ||d<   |	|d<   |j                  |«       ŒG |j                  ˆfd„¬«       |S )zJReturn all groups from eligible categories, ranked by state then hit_rate.ra   c              3  ó    K  — | ]  }d –— Œ y­wrc   rF   re   s     r   rJ   z'GroupManager.ranking.<locals>.<genexpr>Ì  rf   rg   r¹   rh   r   r6   é   )rZ   r\   r[   r1   rW   r±   r²   c                óD   •— ‰j                  | d   d«      | d    | d    fS )Nr&   é	   rW   r"   )r;   )r   Ústate_orders    €r   r€   z&GroupManager.ranking.<locals>.<lambda>Þ  s1   ø€ Ø—‘  -Ñ 0°!Ó4Ø�:‘�Ø�=Ñ!Ð!ð€ r   r�   )	r†   rl   r   r(   rN   r´   rX   rm   r�   )r   r4   ro   rp   rR   r¶   rA   r   rT   rE   rW   rÕ   s              @r   ÚrankingzGroupManager.rankingÉ  sì   ø€ à×'Ñ'¨	Ó2ˆØ—x‘xÑ2¨TÔ2Ó2ˆØ�i‰i×Ñð %!ð
 ". ð /	ð!ð óˆð "#°¸1Ñ=ˆØˆØ—<‘<“>ò 	ˆCÜ�S“	ˆAØ'+×'9Ñ'9¸!¸J¹-Ó'HÑ$ˆE�7˜HØ$ˆAˆj‰MØ#(ˆAÐÑ Ø%,ˆAÐ!Ñ"Ø�M‰M˜!Õð	ð 	�‰óð 	ô 	
ð ˆr   c                ó’  — | j                   j                  d«      }|j                  «       d   }| j                   j                  d«      }|j                  «       d   }| j                   j                  d«      }|j                  «       d   }dj                  d„ t        D «       «      }| j                   j                  d|› d�t        t        «      «      }|j                  «       D �ci c]  }|d   |d	   “Œ }}| j                   j                  d
«      }|j                  «       D �ci c]  }|d   |d	   “Œ }}|||||dœS c c}w c c}w )z/Return summary stats including state breakdown.zSELECT COUNT(*) FROM fb_groupsr   z0SELECT COUNT(*) FROM fb_groups WHERE aktywna = 1zMSELECT COUNT(*) FROM fb_groups WHERE kategoria = 'czesci_tir' AND aktywna = 1ra   c              3  ó    K  — | ]  }d –— Œ y­wrc   rF   re   s     r   rJ   z%GroupManager.stats.<locals>.<genexpr>ò  s   è ø€ ÒA¨¤ÑAùrg   zY
            SELECT group_state, COUNT(*) FROM fb_groups
            WHERE kategoria IN (z+)
            GROUP BY group_state
        r6   zSSELECT kategoria, COUNT(*) FROM fb_groups GROUP BY kategoria ORDER BY COUNT(*) DESC)ÚtotalÚactiveÚactive_czesci_tirÚby_categoryÚby_state)r   r(   Úfetchonerl   rk   rj   rN   )	r   rR   rÙ   rÚ   Ú
active_tirrp   rA   rÝ   Úby_cats	            r   ÚstatszGroupManager.statsæ  sG  € à�i‰i×ÑÐ @ÓAˆØ—‘“˜qÑ!ˆØ�i‰i×ÑÐ RÓSˆØ—‘“ Ñ"ˆØ�i‰i×ÑØ[ó
ˆð —\‘\“^ AÑ&ˆ
ð —x‘xÑAÔ-@ÔAÓAˆØ�i‰i×Ñð %!à!- ð /	ð!ô Ô%Ó&ó	(ˆð
 /2¯l©l«nÖ= s�C˜‘F˜C ™F‘NÐ=ˆÐ=à�i‰i×ÑØaó
ˆð -0¯L©L«NÖ; S�#�a‘&˜#˜a™&‘.Ð;ˆÐ;àØØ!+Ø!Ø ñ
ð 	
ùò >ùò
 <s   Ã&D?Ä%Ec                ó8   — | j                   j                  «        y r{   )r   Úclose)r   s    r   rã   zGroupManager.close  s   € Ø�	‰	�‰Õr   )r   r®   ÚreturnÚNone)rä   rå   )r=   r®   rä   r<   )r1   r®   rQ   r<   rä   ztuple[int, int, float])r1   r®   rä   r®   r{   )rn   ztuple[str, ...] | Nonerä   zdict[str, int])r•   r<   r4   ústr | list[str] | Nonerä   ú
list[dict])r4   ræ   rä   ú	list[str])rµ   r®   rn   rè   rä   rç   )r4   zstr | list[str]rä   rç   )r¶   rç   r•   r<   rä   rç   )r1   r®   rQ   r<   rä   Úfloat)r   )
r1   r®   rE   r<   rM   r<   rÌ   r<   rä   rå   )r1   r®   rä   rå   )r4   ræ   rä   rç   )rä   r´   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   rB   ÚHIT_RATE_WINDOWrX   r_   rw   r«   r†   r‡   rº   r’   rÈ   rÍ   rÏ   rÖ   rá   rã   rF   r   r   r   r   %   sÒ   „ ÙIóó0ólð< ,;ð.Øð.Ø%(ð.à	ó.ó&ô.ðj ;?ðiØðiØ!7ðià	óió^ó&óPó,ð" >Mô ð MNðØðØ&)ðØ14ðØFIðà	óó<6ôó:
ô@r   r   )rí   Ú
__future__r   r8   r¿   r   r   Úpathlibr   rî   r]   r³   rk   rˆ   r‰   rŠ   r   rF   r   r   ú<module>rñ      sZ   ðñõ #ã 
Û Û Ý Ý ð €ð Ð ð €ð WÐ ð €Ø€Ø€÷bò br   