
    źi                     L   U d 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 da	ee
   ed<   daeej                     ed<   de
fdZd	ej                  fd
Zdej                  fdZ	 	 dFde
dee
   dee
   dee   def
dZde
dee   fdZde
defdZdGde
dedefdZde
dedefdZdedefdZde
dee   fdZdHde
de
dee
   de
fdZ	 	 dIde
d e
d!ee
   d"ee
   def
d#Zde
defd$Z	 	 dJde
dee
   d%ee
   dedef
d&Zde
dee   fd'Zdefd(Z de
defd)Z!defd*Z"dKd+edefd,Z#dKd-efd.Z$dee
   dee
   dee
   d/e
d0edefd1Z%	 	 	 	 dLde
d2ee
   d3ee
   d4ee
   d5ee   d6ed7e
d8ee
   defd9Z&de
defd:Z'd;edefd<Z(d=ed>edefd?Z)	 	 	 dMd@e
dAe
dBe
dCe*dedefdDZ+defdEZ,y)Num   
SQLite Database Layer for Battle System
Python 표준 라이브러리만 사용 (sqlite3, json, time, uuid)
    N)Path)Optional_db_path_connectiondb_pathc                    | a t        |       }|j                  j                  dd       t        t              j                  j                  dz  dz  }t        j                  | d      }|j                  d       |j                  d       |j                  d	       |j                         r!|j                         }|j                  |       |at        |       |S )
u   
    데이터베이스 초기화
    - 스키마 파일 실행
    - WAL 모드 설정
    - foreign_keys, busy_timeout 설정
    - 마이그레이션 적용
    T)parentsexist_okschemaszbattle-db-schema.sqlF)check_same_threadzPRAGMA journal_mode=WALzPRAGMA foreign_keys=ONzPRAGMA busy_timeout=5000)r   r   parentmkdir__file__sqlite3connectexecuteexists	read_textexecutescriptr   _apply_migrations)r   db_fileschema_pathconn
schema_sqls        D/home/jooyoung/.openclaw/workspace-260312/orchestration/server/db.pyinit_dbr      s     H 7mGNN5 x.''..:=SSK ??7e<DLL*+LL)*LL+,  **,
:&K dK    r   c                 0   | j                         }|j                  d       |j                         d   xs d}|dk  r	 |j                  d       t        d       |j                  d	       |j                  d
       |j                  d       |j                  dt        j                         f       | j                          t        d       yy# t        j
                  $ r2}dt        |      j                         v rt        d       n Y d}~d}~ww xY w)u   마이그레이션 적용z'SELECT MAX(version) FROM schema_versionr      z4ALTER TABLE game_sessions ADD COLUMN save_state TEXTu)   ✅ Migration v2: Added save_state columnzduplicate columnu6   ⚠️  Migration v2: save_state column already existsNz^CREATE INDEX IF NOT EXISTS idx_sessions_user_game ON game_sessions(user_id, game_id, ended_at)zQCREATE INDEX IF NOT EXISTS idx_battles_adapter_result ON battles(adapter, result)zECREATE INDEX IF NOT EXISTS idx_battles_created ON battles(created_at)zXINSERT OR IGNORE INTO schema_version VALUES (2, ?, 'Add save_state + analytics indexes')u+   ✅ Migration v2: Analytics indexes created)
cursorr   fetchoneprintr   OperationalErrorstrlowertimecommit)r   r    current_versiones       r   r   r   4   s    [[]F NN<=oo'*/aO 	NNQR=> 	wxjk^_ 	qyy{n	&;<)  '' 	!SV\\^3NO P	s   C D#(DDreturnc                  0    t         t        d      t         S )u/   단일 connection 반환 (thread-safe with WAL)z/Database not initialized. Call init_db() first.)r   RuntimeError r   r   get_connectionr.   S   s    LMMr   user_iddevice_hashdisplay_namesettingsc                 *   t               }|j                         }t        j                         }|j                  d| f       |j	                         }|rp|\  }}	}
|r't        j                  |
      }|j                  |       nt        j                  |
      }|j                  d||t        j                  |      ||| f       n9d\  }}	|xs i }|j                  d| |||	t        j                  |      ||||f	       |j                          | ||	||dS )u!   유저 생성 또는 업데이트z3SELECT level, exp, settings FROM users WHERE id = ?a
  
            UPDATE users 
            SET display_name = COALESCE(?, display_name),
                device_hash = COALESCE(?, device_hash),
                settings = ?,
                last_seen = ?,
                updated_at = ?
            WHERE id = ?
           r   z
            INSERT INTO users (id, display_name, level, exp, settings, device_hash, 
                             created_at, last_seen, updated_at)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        )userIdlevelexpdisplayNamer2   )
r.   r    r&   r   r!   jsonloadsupdatedumpsr'   )r/   r0   r1   r2   r   r    nowrowr7   r8   existing_settingsmerged_settingss               r   upsert_userrB   ]   s    D[[]F
))+C NNH7*U
//
C
(+%s% "jj):;O""8,"jj):;O  KO)Dc3PWX	Z 
s".b  |UCO1L3S*		+ 	KKM ## r   c                     t               }|j                         }|j                  d| f       |j                         }|sy|d   |d   |d   |d   |d   t	        j
                  |d         |d	   |d
   |d   |d   d
S )u   유저 조회z
        SELECT id, display_name, level, exp, preferred_locale, settings, 
               device_hash, created_at, last_seen, updated_at
        FROM users WHERE id = ?
    Nr   r5   r                     	   )
r6   r9   r7   r8   preferredLocaler2   
deviceHash	createdAtlastSeen	updatedAtr.   r    r   r!   r:   r;   )r/   r   r    r?   s       r   get_userrQ      s    D[[]F
NN  	 //
C a&1vQ1vq6JJs1v&!fVFV r   c           
      >   t               }|j                         }t        |       }|s| ddddddi dS |j                  d| f       |j	                         }t        d |D              }t        |      |z
  }i }|D ]H  \  }}	|	|vr	dddd||	<   ||	   dxx   dz  cc<   |dk(  r||	   d	xx   dz  cc<   9||	   d
xx   dz  cc<   J |D ]%  }	||	   d   }
|
dkD  r||	   d	   |
z  dz  nd||	   d<   ' | |d   |d   t        |      |||r|t        |      z  dz  |dS d|dS )u/   유저 통계 (기존 API 응답 형태 유지)r5   r   )r6   r7   r8   totalBattleswinslosseswinRateadapterStatszC
        SELECT result, adapter FROM battles WHERE user_id = ?
    c              3   2   K   | ]  }|d    dk(  sd  yw)r   winr5   Nr-   ).0bs     r   	<genexpr>z!get_user_stats.<locals>.<genexpr>   s     3QQqTU]q3s   )rT   rU   totalr]   rY   rT   rU   d   rV   r7   r8   )r.   r    rQ   r   fetchallsumlen)r/   r   r    userbattlesrT   rU   adapter_statsresultadapterr]   s              r   get_user_statsrg      s   D[[]F GD	
 		
 NN 
 ooG3'33D\D F M" 2-'./1q%IM'"gw'1,'U?'"6*a/*'"8,1,2 ! 
g&w/<AAIM'"6*U2S81 	gy)
 gE{G29D3w<'#-%	 	 @A%	 	r   limitc           
          t               }|j                         }|j                  d| |f       g }|j                         D ]/  }|j	                  |d   |d   |d   dk(  |d   |d   |d   d	       1 |S )
u   유저 전투 이력z
        SELECT battle_id, created_at, result, adapter, duration_ms, remaining_hp
        FROM battles 
        WHERE user_id = ?
        ORDER BY created_at DESC
        LIMIT ?
    r   r5   r   rY   rD   rE   rF   )battleId	timestampvictoryrf   durationremainingHP)r.   r    r   r_   append)r/   rh   r   r    rc   r?   s         r   get_user_historyrp      s    D[[]F
NN  5	 G  AQ1v1vAq6
 	 Nr   
exp_gainedc                 ^   t               }|j                         }|j                  d| f       |j                         }|st	        |        d\  }}n|\  }}||z  }|dk\  r|dz  }|dz  }|dk\  r|j                  d||t        j
                         | f       |j                          | |||dS )u%   EXP 업데이트 및 레벨업 처리z)SELECT level, exp FROM users WHERE id = ?r4   r^   r5   z_
        UPDATE users 
        SET level = ?, exp = ?, updated_at = ?
        WHERE id = ?
    )r6   r7   r8   	expGained)r.   r    r   r!   rB   r&   r'   )r/   rq   r   r    r?   r7   r8   s          r   update_user_exprt     s    D[[]F NN>
K
//
CG
s
s :C *s

 *
 NN  diik7	+	- 	KKM 	 r   battle_datac                    t               }|j                         }| j                  dt        t	        j
                                     }| j                  d      }| j                  d      }| j                  d      }| j                  dd      }| j                  dd      }|dk(  r| j                  d      rd	}| j                  d
d      }	d| v r(t        | d   t              r| d   j                  d|	      }	|d	k(  }
|
r|	dz  n|	dz  }d}|rt        ||      }|d   }|j                  d|||||| j                  d      | j                  d      || j                  d      | j                  d      | j                  d      |	|| j                  d      | j                  d      r$t        j                  | j                  d            nd| j                  d      r$t        j                  | j                  d            ndt        j                  | j                  dg             | j                  d      | j                  d      rdnd| j                  d      t        j                  |       | j                  dt        j                               f       |r(|j                  d|
rdnd| j                  d      |f       |j                          t        |       }|j                  ||||d        |S )!u   전투 결과 저장rj   r6   	sessionIdgameIdrf   unknownre   rl   rY   
enemyLevelr5   
enemyStatsr7      rF   a  
        INSERT INTO battles (
            battle_id, user_id, session_id, game_id, adapter,
            battle_slot_id, scenario_node_id, result,
            remaining_hp, turns_used, total_damage, enemy_level, exp_gained,
            duration_ms, player_stats, enemy_stats, special_conditions,
            input_count, is_autoplay, client_build, raw_data, created_at
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    battleSlotIdscenarioNodeIdrn   	turnsUsedtotalDamage
durationMsplayerStatsNspecialConditions
inputCount
isAutoplayr   clientBuildrk   z
            UPDATE game_sessions 
            SET battles_played = battles_played + 1,
                battles_won = battles_won + ?,
                last_node_id = COALESCE(?, last_node_id)
            WHERE session_id = ?
        )rj   rs   	userLevelre   )r.   r    getr$   uuiduuid4
isinstancedictrt   r   r:   r=   r&   r'   r<   )ru   r   r    	battle_idr/   
session_idgame_idrf   re   enemy_level
is_victoryrq   
user_leveluser_resultresponses                  r   insert_battler   /  s   D[[]F
C

,=>Iooh'G-Jooh'Gooi3G __Xy1F{y9 //,2K{"z+l2KT'R!,/33G[I E/J%/r![1_J J%gz: )
 NN  	'()&$&%6Aoom6T

;??=12Z^5@__\5R

;??<01X\

;??#6;<%__\*&

;TYY[1-
D   a1koo6F&GT	V 	KKM K HOO	  Or   r   c                 h   t               }|j                         }|j                  d| f       |j                         }|sy|d   rt	        j
                  |d         ni }i d|d   d|d   d|d	   d
|d   d|d   d|d   d|d   d|d   d|d   d|d   d|d   d|d   d|d   d|d   d |d!   rt	        j
                  |d!         ndd"|d#   rt	        j
                  |d#         ndd$|d%   rt	        j
                  |d%         ng |d&   t        |d'         |d(   |d)   d*|S )+u   전투 결과 조회a  
        SELECT battle_id, user_id, session_id, game_id, adapter,
               battle_slot_id, scenario_node_id, result,
               remaining_hp, turns_used, total_damage, enemy_level, exp_gained,
               duration_ms, player_stats, enemy_stats, special_conditions,
               input_count, is_autoplay, client_build, raw_data, created_at
        FROM battles WHERE battle_id = ?
    N   rj   r   r6   r5   rw   r   rx   rD   rf   rE   r}   rF   r~   rG   re   rH   rn   rI   r   rJ   r   
   rz      rs      r      r      r{   r|   r                  )r   r   r   rk   )r.   r    r   r!   r:   r;   bool)r   r   r    r?   raw_datas        r   
get_battler     s   D[[]F
NN   //
C '*"gtzz#b'"2HCF#a& 	SV 	#a&	
 	3q6 	A 	#a& 	#a& 	s1v 	SV 	s2w 	c"g 	SW 	c"g 	c"gtzz#b'*4  	SWdjjR)$!" 	CGTZZB0#$ "g3r7m2wW+, - r   r   client_buildc                    t               }|j                         }t        t        j                               }t        j
                         }|j                  d|f       |j                         s|j                  d||f       |j                  d| f       |j                         s|j                  d| |||f       |j                  d|| |||f       |j                          |S )u   게임 세션 생성+SELECT game_id FROM games WHERE game_id = ?zl
            INSERT INTO games (game_id, adapters_used, created_at)
            VALUES (?, '[]', ?)
        z!SELECT id FROM users WHERE id = ?z
            INSERT INTO users (id, level, exp, created_at, last_seen, updated_at)
            VALUES (?, 1, 0, ?, ?, ?)
        z
        INSERT INTO game_sessions (
            session_id, user_id, game_id, started_at, client_build
        ) VALUES (?, ?, ?, ?, ?)
    )	r.   r    r$   r   r   r&   r   r!   r'   )r/   r   r   r   r    r   r>   s          r   create_sessionr     s    D[[]FTZZ\"J
))+C NN@7*M??  s^	 NN6
C??  sC%	'
 NN  gw\	:	< 	KKMr   r   
end_reason	ending_iddrop_node_idc           
      F   t               }|j                         }t        j                         }|j                  d||||| f       |j	                          |j                  d| f       |j                         }|sddiS |d   |d   |d   |d   |d	   |d
   |d   |d   |d	S )u   세션 종료z
        UPDATE game_sessions 
        SET ended_at = ?,
            end_reason = ?,
            ending_id = ?,
            drop_node_id = ?
        WHERE session_id = ?
    z
        SELECT session_id, user_id, game_id, started_at, ended_at, 
               battles_played, battles_won, chapters_completed
        FROM game_sessions WHERE session_id = ?
    status	not_foundr   r5   r   rD   rE   rF   rG   rH   )	rw   r6   rx   	startedAtendedAtbattlesPlayed
battlesWonchaptersCompleted	endReason)r.   r    r&   r   r'   r!   )r   r   r   r   r   r    r>   r?   s           r   end_sessionr     s     D[[]F
))+C
NN  z9lJ	?A 	KKM NN  	 //
C+&& Va&a&Vq6Q!f V
 
r   c                    t               }|j                         }dddddd}g d}g }g }i }|j                         D ]  \  }	}
|
||j                  |	|	      <    |j                         D ]  \  }	}
|	|v s|j	                  |	 d       |	dk(  rO|
Mt        |
t        t        f      r%|j	                  t        j                  |
             a|j	                  |
       s|j	                  |
        |sd	d
iS |j	                  |        ddj                  |       d}|j                  ||       |j                          d| dS )u   세션 업데이트last_node_idbattles_playedbattles_wonchapters_completed
save_state)
lastNodeIdr   r   r   	saveState)r   r   r   r   r   z = ?r   
no_updateszUPDATE game_sessions SET z, z WHERE session_id = ?ok)r   rw   )r.   r    itemsr   ro   r   r   listr:   r=   joinr   r'   )r   kwargsr   r    camel_to_snakeallowed_fieldsupdatesvalues
normalizedkeyvaluesqls               r   update_sessionr     sM   D[[]F %)#1!N kNGF Jlln 9
U38
>%%c3/09 !&&( 
%
U. NNcU$<(l"u'8edD\2MM$**U"34MM%(e$
% ,''
MM*%dii&8%99N
OC
NN3KKM44r   r   c                 D   t               }|j                         }dg}| g}|r"|j                  d       |j                  |       |dk(  r|j                  d       n|dk(  r|j                  d       dj                  |      }|j                  |       |j	                  d| d	|       g }	|j                         D ]U  }
d
}|
d   r	 t        j                  |
d         }|	j                  |
d   |
d   |
d   |
d   |
d   |
d   |
d   |
d   |d	       W |	S #  |
d   }Y @xY w)u   
    유저의 세션 목록 조회
    status='active' → ended_at IS NULL
    status='completed' → end_reason='completed'
    zuser_id = ?zgame_id = ?activezended_at IS NULL	completedzend_reason = 'completed' AND z
        SELECT session_id, game_id, started_at, ended_at, end_reason,
               battles_played, battles_won, last_node_id, save_state
        FROM game_sessions
        WHERE z6
        ORDER BY started_at DESC
        LIMIT ?
    NrI   r   r5   r   rD   rE   rF   rG   rH   )	rw   rx   r   r   r   r   r   r   r   )r.   r    ro   r   r   r_   r:   r;   )r/   r   r   rh   r   r    
conditionsparamswhere_clausesessionsr?   r   s               r   get_user_sessionsr   4  sV    D[[]FJYF-(g,-	;	45<<
+L
MM%
NN  n 	 
 H  
q6$!ZZA/
 	Q!fQ1vQ Va&a&#

 
	( O$ V
s   DDc                 J   t               }|j                         }|j                  d| f       |j                         }|syd}|d   r	 t	        j
                  |d         }|d   |d   |d   |d   |d   |d	   |d
   |d   |d   |d   |d   |d   |d   |dS #  |d   }Y AxY w)u(   세션 상세 조회 (save_state 포함)a  
        SELECT session_id, user_id, game_id, started_at, ended_at, end_reason,
               ending_id, chapters_completed, battles_played, battles_won,
               last_node_id, drop_node_id, client_build, save_state
        FROM game_sessions
        WHERE session_id = ?
    Nr   r   r5   r   rD   rE   rF   rG   rH   rI   rJ   r   r   r   )rw   r6   rx   r   r   r   endingIdr   r   r   r   
dropNodeIdr   r   rP   )r   r   r    r?   r   s        r   get_sessionr   m  s    D[[]F
NN   //
CJ
2w	!CG,J
 Va&a&Vq6VF VQ!f"g"g2w 	!RJs   	B B"c                     t               } | j                         }|j                  d       |j                         d   }|j                  d       |j                         d   }|j                  d       |j                         d   }|j                  d       |j                         d   }|j                  d       |j                         d   }|j                  d       |j                         d   }|dkD  r||z  dz  nd}|j                  d	       |j                         d   xs d}	||||||t	        |d
      t	        |	d
      dS )u   글로벌 통계z1SELECT COUNT(DISTINCT user_id) FROM game_sessionsr   z"SELECT COUNT(*) FROM game_sessionsz9SELECT COUNT(*) FROM game_sessions WHERE ended_at IS NULLzASELECT COUNT(*) FROM game_sessions WHERE end_reason = 'completed'zSELECT COUNT(*) FROM battlesz1SELECT COUNT(*) FROM battles WHERE result = 'win'r^   zv
        SELECT AVG((ended_at - started_at) * 1000)
        FROM game_sessions
        WHERE ended_at IS NOT NULL
    r   )uniqueUserstotalSessionsactiveSessionscompletedSessionsrS   rT   rV   avgSessionDurationMs)r.   r    r   r!   round)
r   r    unique_userstotal_sessionsactive_sessionscompleted_sessionstotal_battlesrT   win_rateavg_durations
             r   get_analytics_overviewr     sK   D[[]F NNFG??$Q'L NN78__&q)N NNNOoo'*O NNVW*1- NN12OO%a(M NNFG??QD/<q/@}$s*aH NN  	
 ??$Q',1L $')/%1% %lA 6	 	r   c                 b   t               }|j                         }|j                  d| f       g }d}d}|j                         D ]%  }|d   }|d   }||z  }|j	                  ||d       ' |j                  d| f       |j                         d   }|dkD  r||z  dz  nd}	| |t        |	d      dS )	u.   게임별 퍼널 — battleCount별 세션 수z
        SELECT battles_played, COUNT(*) as session_count
        FROM game_sessions
        WHERE game_id = ?
        GROUP BY battles_played
        ORDER BY battles_played
    r   r5   )battlesCompletedsessionCountzg
        SELECT COUNT(*) FROM game_sessions
        WHERE game_id = ? AND end_reason = 'completed'
    r^   r   )rx   stepscompletionRate)r.   r    r   r_   ro   r!   r   )
r   r   r    r   r   r   r?   battles_completedsession_countcompletion_rates
             r   get_analytics_funnelr     s    D[[]F
NN   ENI  FA-' 1)
 	 NN   !!$I<JQ<Ny>1C7TUO 3 r   c            	         t               } | j                         }|j                  d       i }|j                         D ]  }|d   }|d   }|d   xs d}|d   xs d}||vr
ddg g d||<   ||   dxx   dz  cc<   |dk(  r||   d	xx   dz  cc<   |dkD  r||   d
   j	                  |       |dkD  st||   d   j	                  |        i }|j                         D ]  \  }}|d   }	|d	   }
|	dkD  r|
|	z  dz  nd}|d
   rt        |d
         t        |d
         z  nd}|d   rt        |d         t        |d         z  nd}|	|
t        |d      t        |d      t        |d      d||<    d|iS )u   어댑터별 통계zt
        SELECT adapter, result, turns_used, duration_ms
        FROM battles
        WHERE adapter IS NOT NULL
    r   r5   r   rD   )r]   rT   	turnsListdurationListr]   rY   rT   r   r   r^   )r]   rT   rV   avgTurnsavgDurationMsadapters)	r.   r    r   r_   ro   r   r`   ra   r   )r   r    r   r?   rf   re   turnsrm   statsr]   rT   r   	avg_turnsr   s                 r   get_analytics_adaptersr     s   D[[]F
NN  	 H  ?a&QA!q6;Q(" "	!HW 	'"a'"U?Wf%*%19Wk*11%8a<Wn-44X>+?0 F"..* 
gV}+019D5L3&!IN{I[Ck*+c%2D.EEab	RWXfRgs501Cn8M4NNmn Xq)i+"<3
w
  r   daysc           	         t               }|j                         }t        j                         | dz  z
  }|j                  d|f       |j	                         D ci c]  }|d   |d    }}|j                  d|f       |j	                         D ci c]  }|d   |d    }}t        t        t        |j                               t        |j                               z   D cg c]  }||	 c}            }g }	|D ]7  }
|	j                  |
|j                  |
d      |j                  |
d      d       9 d|	iS c c}w c c}w c c}w )u   일별 세션/전투 수iQ z
        SELECT DATE(started_at, 'unixepoch') as date, COUNT(*) as count
        FROM game_sessions
        WHERE started_at >= ?
        GROUP BY date
        ORDER BY date
    r   r5   z
        SELECT DATE(created_at, 'unixepoch') as date, COUNT(*) as count
        FROM battles
        WHERE created_at >= ?
        GROUP BY date
        ORDER BY date
    )dater   rc   r   )r.   r    r&   r   r_   sortedsetr   keysro   r   )r   r   r    cutoffr?   sessions_by_datebattles_by_dated	all_datestimeliner   s              r   get_analytics_timeliner  *  sY   D[[]FYY[D5L)F NN   39//2CD3AADD NN   281BC#s1vs1v~COC st,<,A,A,C'DtOL`L`LbGc'cu!ghgtAuvwIH (,,T15&**43
 	 H1 E D vs   D;E "E*Etimeout_minutesc                     t               }|j                         }t        j                         | dz  z
  }|j                  dt        j                         |f       |j                  }|j                          d|iS )u)   오래된 진행 중 세션 자동 종료<   z
        UPDATE game_sessions 
        SET ended_at = ?,
            end_reason = 'timeout'
        WHERE ended_at IS NULL 
          AND started_at < ?
    cleaned)r.   r    r&   r   rowcountr'   )r	  r   r    r  updateds        r   cleanup_stale_sessionsr  T  sj    D[[]FYY[Ob01F
NN  ))+v	  ooGKKMwr   
event_type
event_datac           
          t               }|j                         }|j                  d| |||t        j                  |      t        j
                         f       |j                          |j                  S )u   이벤트 로그 저장z
        INSERT INTO events (user_id, session_id, game_id, event_type, event_data, created_at)
        VALUES (?, ?, ?, ?, ?, ?)
    )r.   r    r   r:   r=   r&   r'   	lastrowid)r/   r   r   r  r  r   r    s          r   insert_eventr  l  sa     D[[]F
NN  :w
DJJz4JDIIK	XZ
 	KKMr   
request_idnamegenreadapters_usedbattle_slot_countversionserving_urlc                    t               }|j                         }	t        j                         }
|	j                  d| f       |	j	                         }|r2|	j                  d||||rt        j                  |      nd|||| f       n2|	j                  d| |||t        j                  |xs g       ||||
f	       |j                          | ddS )u*   게임 레지스트리 생성/업데이트r   a  
            UPDATE games 
            SET request_id = COALESCE(?, request_id),
                name = COALESCE(?, name),
                genre = COALESCE(?, genre),
                adapters_used = COALESCE(?, adapters_used),
                battle_slot_count = COALESCE(?, battle_slot_count),
                version = COALESCE(?, version),
                serving_url = COALESCE(?, serving_url)
            WHERE game_id = ?
        Nz
            INSERT INTO games (
                game_id, request_id, name, genre, adapters_used,
                battle_slot_count, version, serving_url, created_at
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        r   )rx   r   )r.   r    r&   r   r!   r:   r=   r'   )r   r  r  r  r  r  r  r  r   r    r>   r   s               r   upsert_gamer    s    
 D[[]F
))+C NN@7*M__F 
 $+8djj'd+w@	A 	 
 z4jj,"-+s<	= 	KKM..r   c                    t               }|j                         }|j                  d| f       |j                         d   }|j                  d| f       |j                         d   }|dkD  r||z  dz  nd}|j                  d| f       |j	                         }i }|D ]7  \  }}	||vrddd||<   ||   dxx   dz  cc<   |	d	k(  s(||   d
xx   dz  cc<   9 |D ]%  }||   d   }
|
dkD  r||   d
   |
z  dz  nd||   d<   ' | ||||dS )u   게임 통계zB
        SELECT COUNT(*) FROM game_sessions WHERE game_id = ?
    r   zh
        SELECT COUNT(*) FROM game_sessions 
        WHERE game_id = ? AND end_reason = 'completed'
    r^   zC
        SELECT adapter, result FROM battles WHERE game_id = ?
    )rT   r]   r]   r5   rY   rT   rV   )rx   	playCountcompletedCountavgCompletionrW   )r.   r    r   r!   r_   )r   r   r    
play_countcompleted_countavg_completionrc   rd   rf   re   r]   s              r   get_game_statsr%    st   D[[]F NN 
 "1%J NN   oo'*O=G!^o
2S8QRN NN 
 ooGM" 0-'./!%<M'"gw'1,'U?'"6*a/*0 ! 
g&w/<AAIM'"6*U2S81 	gy)
 )'% r   
error_datac                    t               }|j                         }| j                  dt        j                               }|j	                  d| j                  dd      | j                  d      | j                  d      | j                  d      | j                  d      | j                  d	d
      | j                  dd      | j                  d      | j                  d      | j                  d      | j                  d      | j                  dd      rdnd| j                  dd      | j                  d      || j                  d      f       |j                          |j                  }|ddS )u   에러 케이스 기록rM   aj  
        INSERT INTO error_cases (
            source, task_label, adapter, phase, model,
            error_type, error_message, error_context,
            resolution, resolution_type, resolution_diff,
            resolved, iterations, time_to_resolve_ms,
            created_at, resolved_at
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    sourcemanual	taskLabelrf   phasemodel	errorTypery   errorMessage errorContext
resolutionresolutionTyperesolutionDiffresolvedFr5   r   
iterationstimeToResolveMs
resolvedAtr   idr   )r.   r    r   r&   r   r'   r  )r&  r   r    
created_aterror_ids        r   insert_errorr<    s,   D[[]FTYY[9J
NN  	x*{#y!ww{I.~r*~&|$'('(^^J.A|Q'()|$!
4 	KKMHd++r   r;  resolution_datac           
         t               }|j                  d|j                  d      |j                  d      |j                  d      t        j                         |j                  d      | f       |j	                          | ddS )u!   에러 해결 기록 업데이트z
        UPDATE error_cases SET
            resolution = ?,
            resolution_type = ?,
            resolution_diff = ?,
            resolved = 1,
            resolved_at = ?,
            iterations = COALESCE(?, iterations)
        WHERE id = ?
    r1  r2  r3  r5  r4  r8  )r.   r   r   r&   r'   )r;  r=  r   s      r   resolve_errorr?  	  s~    DLL 	 	L),-,-		L)
" 	KKMj11r   
error_typer(  keywordresolved_onlyc                 "   t               }t        j                  |_        g }g }|r|j	                  d       | r"|j	                  d       |j	                  |        |r"|j	                  d       |j	                  |       |r+|j	                  d       d| d}|j                  |||g       |rddj                  |       nd}	|j                  d	|	 d
||gz         j                         }
d|_        |
D cg c]  }t        |       c}S c c}w )u9   유사 에러 검색 (Phase 1: 키워드 + 태그 매칭)zresolved = 1zerror_type = ?z
source = ?zC(error_message LIKE ? OR error_context LIKE ? OR resolution LIKE ?)%zWHERE r   r/  z
        SELECT id, source, task_label, adapter, phase, model,
               error_type, error_message, error_context,
               resolution, resolution_type, resolution_diff,
               iterations, created_at
        FROM error_cases
        z6
        ORDER BY created_at DESC
        LIMIT ?
    N)
r.   r   Rowrow_factoryro   extendr   r   r_   r   )r@  r(  rA  rB  rh   r   r   r   kwwhererowsrs               r   search_errorsrL  #  s    D{{DJF.)*+j!,'f_`	^r2rl#3=fW\\*-./2E<< 	 
 	 
5'		 $8: 	 D!"DG"""s   7Dc            
         t               } | j                  d      j                         d   }| j                  d      j                         d   }| j                  d      j                         }| j                  d      j                         }||||z
  |D ci c]  }|d   |d    c}|D ci c]  }|d   s	|d   |d    c}dS c c}w c c}w )u   에러 통계z SELECT COUNT(*) FROM error_casesr   z3SELECT COUNT(*) FROM error_cases WHERE resolved = 1z
        SELECT error_type, COUNT(*) as cnt 
        FROM error_cases 
        GROUP BY error_type 
        ORDER BY cnt DESC
    z
        SELECT resolution_type, COUNT(*) as cnt 
        FROM error_cases 
        WHERE resolved = 1 
        GROUP BY resolution_type 
        ORDER BY cnt DESC
    r5   )r]   r4  
unresolvedbyErrorTypebyResolutionType)r.   r   r!   r_   )r   r]   r4  type_counts
res_countsrK  s         r   get_error_statsrS  O  s    DLL;<EEGJE||QR[[]^_`H ,,   	
 
    	 
  h&,78q!ad
81;DAqtQqT1Q4ZD  9Ds   C
-
C8C)NNN)2   )N)NN)NNr   )   )NNNNr   z1.0N)NNNTrF   )-__doc__r   r:   r&   r   pathlibr   typingr   r   r$   __annotations__r   
Connectionr   r   r.   r   rB   rQ   rg   intr   rp   rt   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r%  r<  r?  r   rL  rS  r-   r   r   <module>r\     s        (3- ,0Xg(() 0"S "H=G.. =>**  <@OS4 48C= 4&sm4>Ftn4X\4lc htn 88C 8D 8tc # t 4&S &c &d &XVt V Vp,# ,(4. ,d!C !# !Xc] !VY !H ,0.2)C )S )#C=)&sm)7;)V+5s +5 +5Z >BAC7s 7Xc] 7&sm7;>7HL7r'C 'HTN 'R0 0d(# ($ (T6  6 p( (d (T C  0(3- Xc] "3-58FJOR& ;?CGOPCG*/ */(3- */sm*/3;C=*/'~*/IL*/ */ 4<C=*/ MQ*/X1C 1D 1n$,T $,d $,N2C 2$ 24 24 9==A )#c )## )#)#6:)#)#%))#X r   