§
    TÂjÜ  ã                  óJ  — d Z ddlm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 ej                             ej                             ej                             e¦  «        d¦  «        ¦  «        Zej                             edd¦  «        Zd	Z G d
„ d¦  «        ZdS )a#  
FreeExile Character Stat Formula Persistence Service.
Manages SQLite storage and historical auditing for stat calculation ASTs.
Table: character_stat_calculations in data/character_stat_formulas.db or :memory:.
Strict typing and context-managed transactions following Elite Standards 2026.
é    )ÚannotationsN)Úcontextmanager)ÚDictÚListÚOptionalÚAnyÚ	Generatorz../..Údatazcharacter_stat_formulas.dba'  
CREATE TABLE IF NOT EXISTS character_stat_calculations (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    player_id TEXT NOT NULL,
    calculation_id TEXT NOT NULL UNIQUE,
    timestamp REAL NOT NULL,
    formula_ast_json TEXT NOT NULL,
    final_stats_json TEXT NOT NULL,
    context_tags_json TEXT NOT NULL,
    created_at TEXT NOT NULL DEFAULT (DATETIME('now'))
);
CREATE INDEX IF NOT EXISTS idx_stat_calc_player ON character_stat_calculations(player_id);
CREATE INDEX IF NOT EXISTS idx_stat_calc_timestamp ON character_stat_calculations(timestamp);
c                  ód   — e Zd ZdZd!d"d„Zd#d
„Zed$d„¦   «         Z	 	 d%d&d„Zd'd„Z	d(d)d„Z
d*d „ZdS )+ÚFormulaPersistenceServicezVAuthoritative persistence service for character stat calculation ASTs and final stats.NÚdb_pathúOptional[str]ÚreturnÚNonec                óø  — |€t           | _        n|| _        | j        dk    | _        d | _        | j        rKt	          j        d¦  «        | _        t          j        | j        _        |                      | j        ¦  «         d S t          j
        t          j                             | j        ¦  «        d¬¦  «         |                      ¦   «         5 }|                      |¦  «         d d d ¦  «         d S # 1 swxY w Y   d S )Nz:memory:T)Úexist_ok)ÚDEFAULT_DB_PATHr   Ú
_is_memoryÚ_memory_connÚsqlite3ÚconnectÚRowÚrow_factoryÚ_init_dbÚosÚmakedirsÚpathÚdirnameÚ_get_connection)Úselfr   Úconns      ú9C:\Projects\FreeExile\server\stats\formula_persistence.pyÚ__init__z"FormulaPersistenceService.__init__&   s  € Øˆ?Ý*ˆDŒLˆLà"ˆDŒLàœ<¨:Ò5ˆŒØ:>ˆÔàŒ?ð 	$Ý '¤°
Ñ ;Ô ;ˆDÔÝ,3¬KˆDÔÔ)Ø�MŠM˜$Ô+Ñ,Ô,Ð,Ð,Ð,åŒK�œŸš¨¬Ñ5Ô5ÀÐEÑEÔEÐEØ×%Ò%Ñ'Ô'ð $¨4Ø—’˜dÑ#Ô#Ð#ð$ð $ð $ñ $ô $ð $ð $ð $ð $ð $ð $ð $øøøð $ð $ð $ð $ð $ð $s   ÃC/Ã/C3Ã6C3r!   úsqlite3.Connectionc                óÆ   — | j         s|                     d¦  «         |                     d¦  «         |                     d¦  «         |                     t          ¦  «         dS )zInitializes tables and pragmas.zPRAGMA journal_mode = WAL;zPRAGMA synchronous = NORMAL;zPRAGMA foreign_keys = ON;N)r   ÚexecuteÚexecutescriptÚDDL_STAT_CALCULATIONS©r    r!   s     r"   r   z"FormulaPersistenceService._init_db8   s`   € àŒð 	7Ø�LŠLÐ5Ñ6Ô6Ð6Ø�ŠÐ3Ñ4Ô4Ð4Ø�ŠÐ0Ñ1Ô1Ð1Ø×ÒÕ0Ñ1Ô1Ð1Ð1Ð1ó    ú)Generator[sqlite3.Connection, None, None]c              #  óœ  K  — | j         r+| j        �$| j        V — | j                             ¦   «          dS t          j        | j        d¬¦  «        }t          j        |_        	 |V — |                     ¦   «          n## t          $ r | 	                    ¦   «          ‚ w xY w	 | 
                    ¦   «          dS # | 
                    ¦   «          w xY w)zBProvides a database connection with automatic commit and rollback.Ng      $@)Útimeout)r   r   Úcommitr   r   r   r   r   Ú	ExceptionÚrollbackÚcloser)   s     r"   r   z)FormulaPersistenceService._get_connection@   sÖ   è è € ð Œ?ð 	˜tÔ0Ð<ØÔ#Ð#Ð#Ð#ØÔ×$Ò$Ñ&Ô&Ð&Ð&Ð&å”? 4¤<¸Ð>Ñ>Ô>ˆDÝ&œ{ˆDÔðØ�
�
�
Ø—’‘”��øÝð ð ð Ø—’‘”�Øðøøøð ð
 —
’
‘”���ø�—
’
‘”��øøøs   Á"A; Á:B5 Á; BÂB5 Â5CÚ	player_idÚstrÚcalculation_idÚformula_astúDict[str, Any]Úfinal_statsúDict[str, float]Úcontext_tagsr   Ú	timestampúOptional[float]Úintc           
     ó¨  — |€t          j         ¦   «         n|}t          j        |d¬¦  «        }t          j        |d¬¦  «        }	t          j        |�|ng d¬¦  «        }
d}|                      ¦   «         5 }|                     ¦   «         }|                     ||||||	|
f¦  «         t          |j        pd¦  «        cddd¦  «         S # 1 swxY w Y   dS )zGPersists a stat calculation AST and resulting stats. Returns record id.NT)Úensure_asciizÍ
        INSERT OR REPLACE INTO character_stat_calculations
        (player_id, calculation_id, timestamp, formula_ast_json, final_stats_json, context_tags_json)
        VALUES (?, ?, ?, ?, ?, ?);
        r   )ÚtimeÚjsonÚdumpsr   Úcursorr&   r<   Ú	lastrowid)r    r2   r4   r5   r7   r9   r:   ÚtsÚast_jsonÚ
stats_jsonÚ	tags_jsonÚqueryr!   rB   s                 r"   Úsave_calculationz*FormulaPersistenceService.save_calculationR   s  € ð &Ð-�TŒY‰[Œ[ˆ[°9ˆÝ”:˜k¸Ð=Ñ=Ô=ˆÝ”Z ¸$Ð?Ñ?Ô?ˆ
Ý”J¨|Ð/G˜|˜|ÈRÐ^bÐcÑcÔcˆ	ðˆð
 ×!Ò!Ñ#Ô#ð 	. tØ—[’[‘]”]ˆFØ�NŠN˜5 9¨n¸bÀ(ÈJÐXaÐ"bÑcÔcÐcÝ�vÔ'Ð,¨1Ñ-Ô-ð	.ð 	.ð 	.ð 	.ñ 	.ô 	.ð 	.ð 	.ð 	.ð 	.ð 	.ð 	.øøøð 	.ð 	.ð 	.ð 	.ð 	.ð 	.s   Á4ACÃCÃCúOptional[Dict[str, Any]]c                óâ  — d}|                       ¦   «         5 }|                     ¦   «         }|                     ||f¦  «         |                     ¦   «         }|€	 ddd¦  «         dS |d         |d         |d         |d         t	          j        |d         ¦  «        t	          j        |d         ¦  «        t	          j        |d	         ¦  «        |d
         dœcddd¦  «         S # 1 swxY w Y   dS )z8Retrieves a single calculation record by calculation_id.zÞ
        SELECT id, player_id, calculation_id, timestamp, formula_ast_json,
               final_stats_json, context_tags_json, created_at
        FROM character_stat_calculations
        WHERE calculation_id = ?;
        NÚidr2   r4   r:   Úformula_ast_jsonÚfinal_stats_jsonÚcontext_tags_jsonÚ
created_at©rL   r2   r4   r:   r5   r7   r9   rP   )r   rB   r&   Úfetchoner@   Úloads)r    r4   rH   r!   rB   Úrows         r"   Úget_calculationz)FormulaPersistenceService.get_calculationk   sN  € ðˆð ×!Ò!Ñ#Ô#ð 	 tØ—[’[‘]”]ˆFØ�NŠN˜5 >Ð"3Ñ4Ô4Ð4Ø—/’/Ñ#Ô#ˆCØˆ{Øð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð ˜$”iØ  Ô-Ø"%Ð&6Ô"7Ø  Ô-Ý#œz¨#Ð.@Ô*AÑBÔBÝ#œz¨#Ð.@Ô*AÑBÔBÝ $¤
¨3Ð/BÔ+CÑ DÔ DØ! ,Ô/ð	ð 	ð	ð 	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð 	ð 	s   —AC$Á'A0C$Ã$C(Ã+C(é
   ÚlimitúList[Dict[str, Any]]c                óö  — d}g }|                       ¦   «         5 }|                     ¦   «         }|                     |||f¦  «         |                     ¦   «         D ]†}|                     |d         |d         |d         |d         t          j        |d         ¦  «        t          j        |d         ¦  «        t          j        |d         ¦  «        |d	         d
œ¦  «         Œ‡	 ddd¦  «         n# 1 swxY w Y   |S )z=Retrieves historical calculations for a player, newest first.a	  
        SELECT id, player_id, calculation_id, timestamp, formula_ast_json,
               final_stats_json, context_tags_json, created_at
        FROM character_stat_calculations
        WHERE player_id = ?
        ORDER BY timestamp DESC
        LIMIT ?;
        rL   r2   r4   r:   rM   rN   rO   rP   rQ   N)r   rB   r&   ÚfetchallÚappendr@   rS   )r    r2   rW   rH   Úresultsr!   rB   rT   s           r"   Úget_player_calculationsz1FormulaPersistenceService.get_player_calculations„   sE  € ðˆð )+ˆØ×!Ò!Ñ#Ô#ð 	 tØ—[’[‘]”]ˆFØ�NŠN˜5 9¨eÐ"4Ñ5Ô5Ð5Ø—’Ñ(Ô(ð 
ð 
�Ø—’Ø˜dœ)Ø!$ [Ô!1Ø&)Ð*:Ô&;Ø!$ [Ô!1Ý#'¤:¨cÐ2DÔ.EÑ#FÔ#FÝ#'¤:¨cÐ2DÔ.EÑ#FÔ#FÝ$(¤J¨sÐ3FÔ/GÑ$HÔ$HØ"% lÔ"3ð	 ð 	 ñ 	ô 	ð 	ð 	ð
ð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð ˆs   ™CC.Ã.C2Ã5C2c                óX   — | j         �"| j                              ¦   «          d| _         dS dS )z(Closes any persistent memory connection.N)r   r1   )r    s    r"   r1   zFormulaPersistenceService.closeŸ   s6   € àÔÐ(ØÔ×#Ò#Ñ%Ô%Ð%Ø $ˆDÔÐÐð )Ð(r*   )N)r   r   r   r   )r!   r$   r   r   )r   r+   )NN)r2   r3   r4   r3   r5   r6   r7   r8   r9   r   r:   r;   r   r<   )r4   r3   r   rJ   )rV   )r2   r3   rW   r<   r   rX   )r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r#   r   r   r   rI   rU   r]   r1   © r*   r"   r   r   #   sÉ   € € € € € Ø`Ð`ð$ð $ð $ð $ð $ð$2ð 2ð 2ð 2ð ðð ð ñ „^ðð. !Ø%)ð.ð .ð .ð .ð .ð2ð ð ð ð2ð ð ð ð ð6%ð %ð %ð %ð %ð %r*   r   )rb   Ú
__future__r   r   r@   r?   r   Ú
contextlibr   Útypingr   r   r   r   r	   r   ÚabspathÚjoinr   Ú__file__ÚPROJECT_ROOTr   r(   r   rc   r*   r"   ú<module>rk      s  ððð ð #Ð "Ð "Ð "Ð "Ð "Ø 	€	€	€	Ø €€€Ø €€€Ø €€€Ø %Ð %Ð %Ð %Ð %Ð %Ø 7Ð 7Ð 7Ð 7Ð 7Ð 7Ð 7Ð 7Ð 7Ð 7Ð 7Ð 7Ð 7Ð 7àŒw�Š˜rœwŸ|š|¨B¬G¯OªO¸HÑ,EÔ,EÀwÑOÔOÑPÔP€Ø”'—,’,˜|¨VÐ5QÑRÔR€ðÐ ð @%ð @%ð @%ð @%ð @%ñ @%ô @%ð @%ð @%ð @%r*   