§
    {»j@#  ã                   óØ   — d Z ddlZddl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mZmZ ddlmZmZ e G d„ d¦  «        ¦   «         Ze G d„ d	¦  «        ¦   «         Z G d
„ d¦  «        ZdS )a  
Isolated Feedback & Suggestions Database Service for FreeExile.
Manages a dedicated database to collect bug reports, gameplay suggestions,
balance adjustments, and system diagnostics from players.
Decoupled completely from game state and financial ledger databases.
é    N)Úcontextmanager)ÚDictÚListÚOptionalÚAnyÚTuple)Ú	dataclassÚasdictc                   óœ   — e Zd ZU dZeed<   dZeed<   dZeed<   dZe	ed<   d	Z
eed
<   dZeed<   dZe	ed<   dZe	ed<   dZe	ed<   dZeed<   dS )ÚSystemDiagnosticsDTOÚiOSÚclient_platformziOS 18.2Ú
os_versionziPhone 16 Pro MaxÚdevice_modelg      ^@Úcurrent_fpsé   Úcurrent_ping_msu   Cá»• Tráº¥n Huyáº¿t LÃ¢nÚcurrent_zone_nameg        Úplayer_xÚplayer_yÚplayer_zzv2.0-AuthoritativeÚgame_build_versionN)Ú__name__Ú
__module__Ú__qualname__r   ÚstrÚ__annotations__r   r   r   Úfloatr   Úintr   r   r   r   r   © ó    ú9C:\Projects\FreeExile\server\feedback\feedback_service.pyr   r      s´   € € € € € € à €O�SÐ Ð Ñ Ø €J�Ð Ð Ñ Ø+€L�#Ð+Ð+Ñ+Ø€K�ÐÐÑØ€O�SÐÐÑØ7Ð�sÐ7Ð7Ñ7Ø€HˆeÐÐÑØ€HˆeÐÐÑØ€HˆeÐÐÑØ2Ð˜Ð2Ð2Ñ2Ð2Ð2r!   r   c                   óš   — e Zd ZU eed<   eed<   eed<   eed<   eed<   eed<   eeef         ed<   eed<   d	Zeed
<   dZ	eed<   dZ
eed<   dS )ÚFeedbackRecordÚfeedback_idÚ	player_idÚplayer_nameÚcategoryÚtitleÚcontentÚdiagnosticsÚstatusÚ Úadmin_responser   Úcreated_at_msÚupdated_at_msN)r   r   r   r   r   r   r   r   r.   r/   r0   r    r!   r"   r$   r$       s›   € € € € € € àÐÐÑØ€N€N�NØÐÐÑØ€M€M�MØ€J€J�JØ€L€L�LØ�c˜3�h”ÐÐÑØ€K€K�KØ€N�CÐÐÑØ€M�3ÐÐÑØ€M�3ÐÐÑÐÐr!   r$   c                   ó*  — e Zd Zddee         fd„Zed„ ¦   «         Zdd„Z	 dde	ded	ed
ededee
         deeeef         fd„Zdedee         fd„Z	 	 	 	 ddee         d	ee         de	de	dee         f
d„Z	 ddedededefd„Zdeeef         fd„ZdS )ÚFeedbackServiceNÚdb_pathc                 ó°  — |st           j                             d¦  «        }|s—t           j                             t           j                             t           j                             t          ¦  «        ddd¦  «        ¦  «        }t          j        |d¬¦  «         t           j                             |d¦  «        }|| _	        |  
                    ¦   «          d S )NÚFEEDBACK_DB_PATHz..ÚdataT)Úexist_okzfeedback_store.db)ÚosÚenvironÚgetÚpathÚabspathÚjoinÚdirnameÚ__file__Úmakedirsr3   Ú_init_database)Úselfr3   Úbase_dirs      r"   Ú__init__zFeedbackService.__init__0   s¨   € Øð 	9Ý”j—n’nÐ%7Ñ8Ô8ˆGØð 	BÝ”w—’¥r¤w§|¢|µB´G·O²OÅHÑ4MÔ4MÈtÐUYÐ[aÑ'bÔ'bÑcÔcˆHÝŒK˜¨4Ð0Ñ0Ô0Ð0Ý”g—l’l 8Ð-@ÑAÔAˆGàˆŒØ×ÒÑÔÐÐÐr!   c              #   óÂ   K  — t          j        | j        ¦  «        }t           j        |_        	 |V — |                     ¦   «          d S # |                     ¦   «          w xY w©N)Úsqlite3Úconnectr3   ÚRowÚrow_factoryÚclose)rB   Úconns     r"   Ú_get_connectionzFeedbackService._get_connection;   sR   è è € åŒ˜tœ|Ñ,Ô,ˆÝ"œ;ˆÔð	ØˆJˆJˆJà�JŠJ‰LŒLˆLˆLˆLøˆD�JŠJ‰LŒLˆLˆLøøøs   ®A ÁAÚreturnc                 óX  — |                       ¦   «         5 }|                     ¦   «         }|                     d¦  «         |                     d¦  «         |                     d¦  «         |                     d¦  «         |                     ¦   «          ddd¦  «         dS # 1 swxY w Y   dS )z1Initializes the dedicated player feedback schema.at  
                CREATE TABLE IF NOT EXISTS player_feedback (
                    feedback_id TEXT PRIMARY KEY,
                    player_id INTEGER NOT NULL,
                    player_name TEXT NOT NULL,
                    category TEXT NOT NULL,
                    title TEXT NOT NULL,
                    content TEXT NOT NULL,
                    diagnostics_json TEXT NOT NULL,
                    status TEXT NOT NULL DEFAULT 'NEW',
                    admin_response TEXT DEFAULT '',
                    created_at_ms INTEGER NOT NULL,
                    updated_at_ms INTEGER NOT NULL
                )
            zICREATE INDEX IF NOT EXISTS idx_feedback_status ON player_feedback(status)zMCREATE INDEX IF NOT EXISTS idx_feedback_category ON player_feedback(category)zLCREATE INDEX IF NOT EXISTS idx_feedback_player ON player_feedback(player_id)N)rM   ÚcursorÚexecuteÚcommit)rB   rL   rP   s      r"   rA   zFeedbackService._init_databaseD   så   € à×!Ò!Ñ#Ô#ð 	 tØ—[’[‘]”]ˆFØ�NŠNð ñ ô ð ð �NŠNÐfÑgÔgÐgØ�NŠNÐjÑkÔkÐkØ�NŠNÐiÑjÔjÐjØ�KŠK‰MŒMˆMð)	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð 	ð 	s   •A=BÂB#Â&B#r&   r'   r(   r)   r*   r+   c                 ó   — |                      ¦   «         }|                      ¦   «         }|sdS t          |¦  «        dk     rdS dt          t          j        ¦   «         ¦  «        › dt	          j        ¦   «         j        dd…         › �}t          t          j        ¦   «         dz  ¦  «        }|rt          |¦  «        nt          t          ¦   «         ¦  «        }		 |  	                    ¦   «         5 }
|
 
                    ¦   «         }|                     d	||||||t          j        |	d
¬¦  «        ||f	¦  «         |
                     ¦   «          ddd¦  «         n# 1 swxY w Y   d}d||fS # t          $ r}d
ddt!          |¦  «        › �fcY d}~S d}~ww xY w)z{
        Submits new player feedback into the dedicated database.
        Returns: (success, feedback_id, message)
        )Fr-   u2   TiÃªu Ä‘á»� gÃ³p Ã½ khÃ´ng Ä‘Æ°á»£c Ä‘á»ƒ trá»‘ng!é
   )Fr-   u8   Ná»™i dung gÃ³p Ã½ pháº£i cÃ³ tá»‘i thiá»ƒu 10 kÃ½ tá»±!Úfb_Ú_Né   éè  aU  
                    INSERT INTO player_feedback (
                        feedback_id, player_id, player_name, category,
                        title, content, diagnostics_json, status,
                        admin_response, created_at_ms, updated_at_ms
                    ) VALUES (?, ?, ?, ?, ?, ?, ?, 'NEW', '', ?, ?)
                F)Úensure_asciius   Cáº£m Æ¡n Ä‘áº¡i hiá»‡p Ä‘Ã£ gá»­i gÃ³p Ã½! Ban Quáº£n Trá»‹ FreeExile Ä‘Ã£ ghi nháº­n vÃ o sá»• bá»™ Ä‘á»™c láº­p.Tr-   u%   Lá»—i há»‡ thá»‘ng khi lÆ°u gÃ³p Ã½: )ÚstripÚlenr   ÚtimeÚuuidÚuuid4Úhexr
   r   rM   rP   rQ   ÚjsonÚdumpsrR   Ú	Exceptionr   )rB   r&   r'   r(   r)   r*   r+   r%   Únow_msÚ	diag_dictrL   rP   Úack_msgÚes                 r"   Úsubmit_feedbackzFeedbackService.submit_feedback\   sæ  € ð —’‘”ˆØ—-’-‘/”/ˆàð 	SØRÐRÝˆw‰<Œ<˜"ÒÐØXÐXàE�C¥¤	¡¤Ñ,Ô,ÐEÐE­t¬z©|¬|Ô/?ÀÀÀÔ/CÐEÐEˆÝ•T”Y‘[”[ 4Ñ'Ñ(Ô(ˆØ+6ÐZ•F˜;Ñ'Ô'Ð'½FÕCWÑCYÔCYÑ<ZÔ<Zˆ	ð	OØ×%Ò%Ñ'Ô'ð ¨4ØŸš™œ�Ø—’ð  ð   ¨K¸Ø˜7¥D¤J¨yÀuÐ$MÑ$MÔ$MØ˜Fðñ
ô 
ð 
ð —’‘”�ðð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð LˆGØ˜ gÐ-Ð-øåð 	Oð 	Oð 	OØ˜"ÐNÅcÈ!ÁfÄfÐNÐNÐNÐNÐNÐNÐNÐNÐNøøøøð	OøøøsC   ÃE$ Ã*AEÅE$ ÅEÅE$ ÅEÅ	E$ Å$
FÅ.FÆFÆFr%   c                 óØ  — |                       ¦   «         5 }|                     ¦   «         }|                     d|f¦  «         |                     ¦   «         }|s	 d d d ¦  «         d S t	          |d         |d         |d         |d         |d         |d         t          j        |d         ¦  «        |d	         |d
         |d         |d         ¬¦  «        cd d d ¦  «         S # 1 swxY w Y   d S )Nz3SELECT * FROM player_feedback WHERE feedback_id = ?r%   r&   r'   r(   r)   r*   Údiagnostics_jsonr,   r.   r/   r0   ©r%   r&   r'   r(   r)   r*   r+   r,   r.   r/   r0   )rM   rP   rQ   Úfetchoner$   r`   Úloads)rB   r%   rL   rP   Úrows        r"   Úget_feedback_by_idz"FeedbackService.get_feedback_by_id‹   sQ  € Ø×!Ò!Ñ#Ô#ð 	 tØ—[’[‘]”]ˆFØ�NŠNÐPÐS^ÐR`ÑaÔaÐaØ—/’/Ñ#Ô#ˆCØð Øð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	õ "Ø Ô.Ø˜kÔ*Ø Ô.Ø˜ZœØ˜'”lØ˜IœÝ œJ sÐ+=Ô'>Ñ?Ô?Ø˜8”}Ø"Ð#3Ô4Ø! /Ô2Ø! /Ô2ðñ ô ð	ð 	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð 	ð 	s   •ACÁ%A-CÃC#Ã&C#é2   r   r,   ÚlimitÚoffsetc                 ó˜  — d}g }|r|dz  }|                      |¦  «         |r|dz  }|                      |¦  «         |dz  }|                     ||g¦  «         g }|                      ¦   «         5 }|                     ¦   «         }	|	                     ||¦  «         |	                     ¦   «         D ]ƒ}
|                      t          |
d         |
d         |
d         |
d         |
d	         |
d
         t          j        |
d         ¦  «        |
d         |
d         |
d         |
d         ¬¦  «        ¦  «         Œ„	 d d d ¦  «         n# 1 swxY w Y   |S )Nz'SELECT * FROM player_feedback WHERE 1=1z AND status = ?z AND category = ?z- ORDER BY created_at_ms DESC LIMIT ? OFFSET ?r%   r&   r'   r(   r)   r*   ri   r,   r.   r/   r0   rj   )	ÚappendÚextendrM   rP   rQ   Úfetchallr$   r`   rl   )rB   r,   r(   rp   rq   ÚqueryÚparamsÚresultsrL   rP   rm   s              r"   Úlist_feedbackszFeedbackService.list_feedbacks¡   s´  € ð :ˆØˆàð 	"ØÐ&Ñ&ˆEØ�MŠM˜&Ñ!Ô!Ð!Øð 	$ØÐ(Ñ(ˆEØ�MŠM˜(Ñ#Ô#Ð#àÐ@Ñ@ˆØ�Š�u˜f�oÑ&Ô&Ð&à(*ˆØ×!Ò!Ñ#Ô#ð 	 tØ—[’[‘]”]ˆFØ�NŠN˜5 &Ñ)Ô)Ð)Ø—’Ñ(Ô(ð ð �Ø—’�~Ø # MÔ 2Ø! +Ô.Ø # MÔ 2Ø  œ_Ø˜gœ,Ø 	œNÝ $¤
¨3Ð/AÔ+BÑ CÔ CØ˜xœ=Ø#&Ð'7Ô#8Ø"% oÔ"6Ø"% oÔ"6ð ñ  ô  ñ ô ð ð ðð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð" ˆs   Á/CD?Ä?EÅEr-   Ú
new_statusr.   c                 óR  — h d£}||vrdS t          t          j        ¦   «         dz  ¦  «        }|                      ¦   «         5 }|                     ¦   «         }|                     d||||f¦  «         |                     ¦   «          |j        dk    cddd¦  «         S # 1 swxY w Y   dS )zk
        Updates feedback status (UNDER_REVIEW, PLANNED, RESOLVED, REJECTED) and logs admin notes.
        >   ÚNEWÚPLANNEDÚREJECTEDÚRESOLVEDÚUNDER_REVIEWFrX   z 
                UPDATE player_feedback
                SET status = ?, admin_response = ?, updated_at_ms = ?
                WHERE feedback_id = ?
            r   N)r   r\   rM   rP   rQ   rR   Úrowcount)rB   r%   rz   r.   Úvalid_statusesrc   rL   rP   s           r"   Úupdate_feedback_statusz&FeedbackService.update_feedback_statusÉ   sý   € ð TÐSÐSˆØ˜^Ð+Ð+Ø�5å•T”Y‘[”[ 4Ñ'Ñ(Ô(ˆØ×!Ò!Ñ#Ô#ð 	' tØ—[’[‘]”]ˆFØ�NŠNð ð ˜n¨f°kÐBñ	Dô Dð Dð
 �KŠK‰MŒMˆMØ”? QÒ&ð	'ð 	'ð 	'ð 	'ñ 	'ô 	'ð 	'ð 	'ð 	'ð 	'ð 	'ð 	'øøøð 	'ð 	'ð 	'ð 	'ð 	'ð 	's   ÁABÂB Â#B c                 óÌ  — i i ddœ}|                       ¦   «         5 }|                     ¦   «         }|                     d¦  «         |                     ¦   «         D ]/}|d         |d         |d         <   |dxx         |d         z  cc<   Œ0|                     d¦  «         |                     ¦   «         D ]}|d         |d	         |d
         <   Œ	 ddd¦  «         n# 1 swxY w Y   |S )z5Provides statistics for GM / Product Team dashboards.r   )Ú	by_statusÚby_categoryÚtotalzCSELECT status, COUNT(*) as cnt FROM player_feedback GROUP BY statusÚcntr…   r,   r‡   zGSELECT category, COUNT(*) as cnt FROM player_feedback GROUP BY categoryr†   r(   N)rM   rP   rQ   ru   )rB   ÚmetricsrL   rP   rm   s        r"   Úget_feedback_metricsz$FeedbackService.get_feedback_metricsá   sN  € à02À2ÐPQÐ"RÐ"RˆØ×!Ò!Ñ#Ô#ð 		E tØ—[’[‘]”]ˆFØ�NŠNÐ`ÑaÔaÐaØ—’Ñ(Ô(ð /ð /�Ø69¸%´j�˜Ô$ S¨¤]Ñ3Ø˜Ð Ð Ô  C¨¤JÑ.Ð Ð Ñ Ð à�NŠNÐdÑeÔeÐeØ—’Ñ(Ô(ð Eð E�Ø:=¸e¼*�˜Ô& s¨:¤Ñ7Ð7ðEð		Eð 		Eð 		Eñ 		Eô 		Eð 		Eð 		Eð 		Eð 		Eð 		Eð 		Eøøøð 		Eð 		Eð 		Eð 		Eð ˆs   ›B1CÃCÃ CrF   )rN   N)NNro   r   )r-   )r   r   r   r   r   rD   r   rM   rA   r   r   r   Úboolrg   r$   rn   r   ry   rƒ   r   r   rŠ   r    r!   r"   r2   r2   /   sÚ  € € € € € ð	ð 	 ¨¤ð 	ð 	ð 	ð 	ð ðð ñ „^ððð ð ð ð> 7;ð-Oð -Oàð-Oð ð-Oð ð	-Oð
 ð-Oð ð-Oð Ð2Ô3ð-Oð 
ˆt�S˜#ˆ~Ô	ð-Oð -Oð -Oð -Oð^¨cð °h¸~Ô6Nð ð ð ð ð0 !%Ø"&ØØð&ð &à˜”ð&ð ˜3”-ð&ð ð	&ð
 ð&ð 
ˆnÔ	ð&ð &ð &ð &ðX !ð	'ð 'àð'ð ð'ð ð	'ð
 
ð'ð 'ð 'ð 'ð0 d¨3°¨8¤nð ð ð ð ð ð r!   r2   )Ú__doc__r8   rG   r`   r]   r\   Ú
contextlibr   Útypingr   r   r   r   r   Údataclassesr	   r
   r   r$   r2   r    r!   r"   ú<module>r�      s6  ððð ð 
€	€	€	Ø €€€Ø €€€Ø €€€Ø €€€Ø %Ð %Ð %Ð %Ð %Ð %Ø 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ø )Ð )Ð )Ð )Ð )Ð )Ð )Ð )ð ð
3ð 
3ð 
3ð 
3ð 
3ñ 
3ô 
3ñ „ð
3ð ðð ð ð ð ñ ô ñ „ðð@ð @ð @ð @ð @ñ @ô @ð @ð @ð @r!   