
    UiH                         d Z ddlZddlmZmZ  ed          Z e            ZdD ]/Z	dD ]*Z
dD ]%ZdD ] Ze                    e	 e
 d	e e            !&+0d
edefdZd-d
edededefdZd
edededededefdZdededededededededededefdZd
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.ded!ededefd"Zdedefd#Zded$edefd%Zded$ed&edefd'Zdededz  fd(Zd.ded$ed)ed*edef
d+Z dedefd,Z!dS )/u%  
==============================================================================
Goalskill DB 모듈 - Goalskill_DB CRUD 레이어
==============================================================================
48개 테이블({H|S}{A|B|C|D}_{T|P|R}{I|M})에 대한 동적 INSERT/SELECT 함수.
    N)get_db_configloggerGoalskill_DB)HSABCD)TPR)IM_
table_namereturnc                     | t           v S )uD   테이블명이 48개 중 하나인지 검증 (SQL Injection 방지))VALID_TABLES)r   s    #/app/app/models/goalskill_module.py_validate_table_namer      s    %%    
session_idoutput_textc           
      r   t          |           st          d|            d}	 t          j        j        di t
          }|                                }d|  d}|                    ||||f           |                                 |j	        }t          j        d|  d| d| d|            ||r)|                                 |                                 S S # t          $ r!}t          j        d	|  d
|            |d}~ww xY w# |r)|                                 |                                 w w xY w)u|  
    Goalskill_DB 테이블에 text 데이터 저장.
    T/P/R 모든 타입에서 공통으로 사용. (A/C/D 파트)

    Args:
        table_name: 테이블명 (예: "HA_PI", "SA_TM")
        session_id: 유저 세션 ID
        output_text: 저장할 텍스트
        status: 컨디션 점수 (1~10). None이면 NULL로 저장.

    Returns:
        저장된 row의 id
    Invalid table name: NINSERT INTO `zE` (session_id, output, status, created_at) VALUES (%s, %s, %s, NOW())z[Goalskill DB] Saved to 
: session=, id=	, status=z[Goalskill DB] Save Error ():  r   
ValueErrormysql	connectorconnectGOALSKILL_DB_CONFIGcursorexecutecommit	lastrowidr   infoclose	Exceptionerror)	r   r   r   statusconnr*   sqlrow_ides	            r   save_to_goalskill_tabler7       sr     
++ ><
<<===D&==)<==ojooosZf=>>>!ozooZooV\oogmooppp  	LLNNNJJLLLL		    E:EE!EEFFF  	LLNNNJJLLLL	s$   B
C 
D%DDD	 	-D6textsource_typer2   c                    t          |           st          d|            d}	 t          j        j        di t
          }|                                }d|  d}|                    |||||f           |                                 |j	        }t          j        d|  d| d| d| d	| d
|            ||r)|                                 |                                 S S # t          $ r!}	t          j        d|  d|	            |	d}	~	ww xY w# |r)|                                 |                                 w w xY w)uw  
    B파트 전용: Goalskill_DB 테이블에 수치 데이터 저장.
    source_type(learning/mindset)과 Gemini status(1~10)를 저장.

    Args:
        table_name: 테이블명 (예: "HB_TM", "SB_PM")
        session_id: 유저 세션 ID
        source_type: "learning" 또는 "mindset"
        status: 1~10 Gemini 점수

    Returns:
        저장된 row의 id
    r   Nr   zV` (session_id, output, source_type, status, created_at) VALUES (%s, %s, %s, %s, NOW())z[Goalskill DB] Saved score to r   z, text=z	, source=r!   r    z![Goalskill DB] Save Score Error (r"   r#   r$   )
r   r   r8   r9   r2   r3   r*   r4   r5   r6   s
             r   save_to_goalskill_table_scorer;   G   s      
++ ><
<<===D&==)<==.J . . . 	
 	sZ{FCDDD!eZ e e!e e*.e e9De eOUe e\be e	
 	
 	
   	LLNNNJJLLLL		    KKKKKLLL  	LLNNNJJLLLL	s$   BC" "
D,DDD -D=senderpart
input_text	h_scoring	s_scoring	t_scoring	p_scoring	r_scoringresult_tablec
                    d}
	 t          j        j        di t          }
|
                                }d}|                    || |||||||||	f
           |
                                 |j        }t          j	        d|	 d|            ||
r)|
                                 |

                                 S S # t          $ rN}t          j        d|            Y d}~|
r*|
                                 |

                                 dS dS d}~ww xY w# |
r)|
                                 |

                                 w w xY w)u  
    admin 테이블에 분류 점수 로그 저장.
    어떤 기준으로 해당 테이블에 분류되었는지 확인할 수 있도록
    각 카테고리별 키워드 점수를 기록합니다.

    Args:
        session_id: 유저 세션 ID
        sender: "I" (AI) 또는 "M" (User)
        part: "A" / "B" / "C" / "D"
        input_text: 원문 텍스트
        h_scoring: H(큰 목표) 키워드 점수
        s_scoring: S(작은 목표) 키워드 점수
        t_scoring: T(대화) 최종 점수
        p_scoring: P(조언) 최종 점수
        r_scoring: R(방향성) 최종 점수
        result_table: 최종 분류된 테이블명

    Returns:
        저장된 row의 id
    NzINSERT INTO `admin` (session_id, sender, part, input_text, H_scoring, S_scoring, T_scoring, P_scoring, R_scoring, result_table, created_at) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW())z&[Goalskill DB] Admin log saved: table=r    z%[Goalskill DB] Admin Log Save Error: r   r#   )r&   r'   r(   r)   r*   r+   r,   r-   r   r.   r/   r0   r1   )r   r<   r=   r>   r?   r@   rA   rB   rC   rD   r3   r*   r4   r5   r6   s                  r   save_admin_logrF   x   s   @ D&==)<==E 	 	sjyy)	
 	 	 	 	!X\XXPVXXYYY  	LLNNNJJLLLL	    @Q@@AAAqqq 	LLNNNJJLLLLL	 	
  	LLNNNJJLLLL	s*   BB7 7
DD
D 
DD -D?c                    t          |           st          d|            d}	 t          j        j        d	i t
          }|                    d          }d|  d}|                    ||f           |                                }||r)|	                                 |	                                 S S # t          $ rQ}t          j        d|  d|            g cY d}~|r)|	                                 |	                                 S S d}~ww xY w# |r)|	                                 |	                                 w w xY w)
u   
    특정 세션의 모든 데이터를 조회.

    Args:
        table_name: 테이블명 (예: "HA_PI")
        session_id: 유저 세션 ID

    Returns:
        [{"id": 1, "session_id": "...", "output": "...", "created_at": "..."}]
    r   NT
dictionarySELECT * FROM `/` WHERE session_id = %s ORDER BY created_at ASCz[Goalskill DB] Get Error (r"   r#   )r   r%   r&   r'   r(   r)   r*   r+   fetchallr/   r0   r   r1   )r   r   r3   r*   r4   resultsr6   s          r   get_from_goalskill_tablerN      sk     
++ ><
<<===D&==)<==--[
[[[sZM***//##  	LLNNNJJLLLL		    D*DDDDEEE					 	LLNNNJJLLLL		  	LLNNNJJLLLL	s0   A#B4 4
D>D
DD 
DD -D?c                    t          |           st          d|            d}	 t          j        j        d	i t
          }|                    d          }d|  d}|                    ||f           |                                }|pi 	 |r)|	                                 |	                                 S S # t          $ rQ}t          j        d|  d|            i cY d}~|r)|	                                 |	                                 S S d}~ww xY w# |r)|	                                 |	                                 w w xY w)
u8   
    특정 세션의 최신 데이터 1건 조회.
    r   NTrH   rJ   z8` WHERE session_id = %s ORDER BY created_at DESC LIMIT 1z![Goalskill DB] Get Latest Error (r"   r#   )r   r%   r&   r'   r(   r)   r*   r+   fetchoner/   r0   r   r1   )r   r   r3   r*   r4   resultr6   s          r   get_latest_from_goalskill_tablerR      sr     
++ ><
<<===D&==)<==--d
dddsZM***""|  	LLNNNJJLLLL		    KKKKKLLL					 	LLNNNJJLLLL		  	LLNNNJJLLLL	s0   A%B7 7
DDDD DD -Ec                 |   i }d}	 t          j        j        di t          }|                    d          }t          t                    D ]:}d| d}|                    || f           |                                }|r|||<   ;||r)|	                                 |	                                 S S # t          $ rN}t          j        d|            i cY d}~|r)|	                                 |	                                 S S d}~ww xY w# |r)|	                                 |	                                 w w xY w)u   
    유저의 모든 Goalskill_DB 데이터를 48개 테이블에서 수집.

    Returns:
        {
            "HA_PI": [{"id": 1, "output": "..."}],
            "HA_TI": [{"id": 2, "output": 1}],
            ...
        }
    NTrH   rJ   rK   z[Goalskill DB] Get All Error: r#   )r&   r'   r(   r)   r*   sortedr   r+   rL   r/   r0   r   r1   )r   rQ   r3   r*   r   r4   rowsr6   s           r   get_all_goalskill_datarV      sk    FD&==)<==-- .. 	* 	*J_J___CNN3...??$$D *%)z"  	LLNNNJJLLLL		    9a99:::					 	LLNNNJJLLLL		  	LLNNNJJLLLL	s0   BB3 3
D=DDD DD -D;
goal_scopec                    d}d}	 t          j        j        di t          }|                                }|r|gnddg}|r|gng d}ddg}|D ]S}	|D ]N}
|D ]I}|	 |
 d| }d	| d
}|                    || f           |                                }|r||d         z  }JOT||r)|                                 |                                 S S # t          $ rN}t          j
        d|            Y d}~|r*|                                 |                                 dS dS d}~ww xY w# |r)|                                 |                                 w w xY w)u   
    특정 세션의 대화 횟수 합계를 조회.

    Args:
        session_id: 세션 ID
        goal_scope: "H" 또는 "S" (None이면 모두)
        part: "A"~"D" (None이면 모두)

    Returns:
        대화 횟수 합계
    Nr   r   r   r   r   r   _TzSELECT COUNT(*) FROM `z` WHERE session_id = %sz![Goalskill DB] Talk Count Error: r#   r&   r'   r(   r)   r*   r+   rP   r/   r0   r   r1   )r   rW   r=   r3   totalr*   scopespartssendersspr<   r   r4   rowr6   s                   r   get_talk_countrb   "  s    DE&==)<== ",;*#s8$8$8$8* 	( 	(A ( (% ( (F$%!4q!4!4F!4!4JV:VVVCNN3666 //++C (Q((   	LLNNNJJLLLL		    <<<===qqq 	LLNNNJJLLLLL	 		  	LLNNNJJLLLL	s*   BC 
D&D!/D) !D&&D) )-Ec                 V   d}	 t          j        j        di t          }|                                }d}|                    || f           |                                }|r|d         |d         nd	 |r)|                                 |                                 S S # t          $ rN}t          j
        d|            Y d}~|r*|                                 |                                 dS dS d}~ww xY w# |r)|                                 |                                 w w xY w)um   
    result テーブルから現在の最大daily番号を取得。
    行がなければ0を返す。
    Nz5SELECT MAX(daily) FROM `result` WHERE session_id = %sr   z%[Result DB] Get Current Daily Error: r#   rZ   )r   r3   r*   r4   ra   r6   s         r   get_current_dailyrd   S  sG   
 D&==)<==EsZM***oo:Q!3s1vv:
  	LLNNNJJLLLL		    @Q@@AAAqqq 	LLNNNJJLLLLL	 		  	LLNNNJJLLLL	s*   A/B   
C8*C3C; 3C88C; ;-D(dailyc           	      (   d}	 t          j        j        di t          }|                                }d}|                    || |f           |                                }|rVt          j        d|  d| d|d                     |d         |r)|	                                 |	                                 S S d}|                    || d|f           |
                                 |j        }t          j        d	|  d| d|            ||r)|	                                 |	                                 S S # t          $ r}t          j        d
|            |d}~ww xY w# |r)|	                                 |	                                 w w xY w)u   
    result テーブルに新しい行を作成（カリキュラム日次の開始）。
    既に同じdailyの行がある場合は作成しない。

    Returns:
        作成された行のid。既に存在する場合は既存行のid。
    Nz<SELECT id FROM `result` WHERE session_id = %s AND daily = %sz([Result DB] Row already exists: session=, daily=r    r   zWINSERT INTO `result` (session_id, output, daily, created_at) VALUES (%s, %s, %s, NOW()) z[Result DB] Created: session=z[Result DB] Create Error: r#   )r&   r'   r(   r)   r*   r+   rP   r   r.   r/   r,   r-   r0   r1   )	r   re   r3   r*   	check_sqlexistingr4   r5   r6   s	            r   create_result_rowrk   i  s    D&==)<== S	y:u"5666??$$ 	Kp:ppW\ppcklmcnppqqqA;  	LLNNNJJLLLL	 hsZU3444!\J\\\\TZ\\]]]  	LLNNNJJLLLL		    5!55666  	LLNNNJJLLLL	s+   B	D9 9AD9 9
E!EE!!E$ $-Fscorec                    d}	 t          j        j        d	i t          }|                                }d}|                    ||| |f           |                                 t          j        d| d|  d|            |j	        dk    |r)|
                                 |
                                 S S # t          $ rN}t          j        d|            Y d}~|r*|
                                 |
                                 dS dS d}~ww xY w# |r)|
                                 |
                                 w w xY w)
u   
    result テーブルの condition_score を更新。

    Args:
        session_id: セッションID
        daily: カリキュラム日次番号
        score: コンディションスコア (1~10)

    Returns:
        更新成功ならTrue
    NzMUPDATE `result` SET condition_score = %s WHERE session_id = %s AND daily = %sz$[Result DB] Updated condition_score=r   rg   r   z*[Result DB] Update Condition Score Error: Fr#   )r&   r'   r(   r)   r*   r+   r,   r   r.   rowcountr/   r0   r1   )r   re   rl   r3   r*   r4   r6   s          r   update_result_condition_scorero     sb    D&==)<==]sUJ6777g5ggJgg`egghhh"  	LLNNNJJLLLL		    E!EEFFFuuu 	LLNNNJJLLLLL	 		  	LLNNNJJLLLL	s*   BB5 5
D?DD DD -D=c           	         d}	 t          j        j        di t          }|                                }ddg}g }|D ][}d| d}|                    || f           |                                }|D ]%}|d         |                    |d                    &\|s/	 |r*|                                 |                                 dS dS t          |          t          |          z  }	t          dt          dt          |	                              }
t          j        d	| d
|	dd|
            |
|r)|                                 |                                 S S # t           $ rN}t          j        d|            Y d}~|r*|                                 |                                 dS dS d}~ww xY w# |r)|                                 |                                 w w xY w)uH  
    48個テーブルから今日のcondition_score(status)の平均を集計。
    A'パート終了時に呼び出し、result テーブルに保存する用。

    対象テーブル: SA_TM, HA_TM (A パート、ユーザー発話のみ)

    Returns:
        平均スコア (1~10の整数) or None (データなし)
    NSA_TMHA_TMz%
                SELECT status FROM `z` 
                WHERE session_id = %s 
                AND status IS NOT NULL 
                AND DATE(created_at) = CURDATE()
            r      
   z"[Result DB] AVG condition: scores=z, avg=z.1fz	, result=z+[Result DB] Get AVG Condition Score Error: r#   )r&   r'   r(   r)   r*   r+   rL   appendr/   sumlenmaxminroundr   r.   r0   r1   )r   r3   r*   target_tables
all_scorestabler4   rU   ra   avgrQ   r6   s               r   get_avg_condition_scorer     s>    D#&==)<== !'*
" 	. 	.E%*  C NN3...??$$D . .q6%%%c!f---.  	  	LLNNNJJLLLLL	 	 *ooJ/QBc

++,,eee3eee]ceefff  	LLNNNJJLLLL		    F1FFGGGttt 	LLNNNJJLLLLL	 		  	LLNNNJJLLLL	s1   BE A)E 
F5'F0>F8 0F55F8 8-G%mindset_scoreunderstanding_scorec           
         ||dS d}	 t          j        j        di t          }|                                }g }g }|*|                    d           |                    |           |*|                    d           |                    |           |                    | |g           dd                    |           d}|                    |t          |                     |
                                 t          j        d|  d	| d
| d|            |j        dk    |r)|                                 |                                 S S # t          $ rN}	t          j        d|	            Y d}	~	|r*|                                 |                                 dS dS d}	~	ww xY w# |r)|                                 |                                 w w xY w)u  
    result テーブルの mindset_score, understanding_score を更新。
    B パートのデイリーチェック完了時に呼び出す。

    Args:
        session_id: セッションID
        daily: カリキュラム日次番号
        mindset_score: マインドセットスコア (1~10), Noneなら更新しない
        understanding_score: 理解度スコア (1~10), Noneなら更新しない

    Returns:
        更新成功ならTrue
    NFzmindset_score = %szunderstanding_score = %szUPDATE `result` SET z, z% WHERE session_id = %s AND daily = %sz&[Result DB] Updated B scores: session=rg   z
, mindset=z, understanding=r   z#[Result DB] Update B Scores Error: r#   )r&   r'   r(   r)   r*   ru   extendjoinr+   tupler,   r   r.   rn   r/   r0   r1   )
r   re   r   r   r3   r*   	set_partsparamsr4   r6   s
             r   update_result_b_scoresr     s3    !4!<uD&==)<== 	$1222MM-(((*7888MM-...z5)***`TYYy%9%9```sE&MM***LZ L L L L$L L6IL L	
 	
 	
 "  	LLNNNJJLLLL		    >1>>???uuu 	LLNNNJJLLLLL	 		  	LLNNNJJLLLL	s*   DE 
F*F%3F- %F**F- --Gc                    d}	 t          j        j        d	i t          }|                    d          }d}|                    || f           |                                }d |D             }t          j        d|  d|            ||r)|	                                 |	                                 S S # t          $ rN}t          j        d|            g cY d}~|r)|	                                 |	                                 S S d}~ww xY w# |r)|	                                 |	                                 w w xY w)
uK  
    result テーブルから最近2回分のcondition_scoreをdaily降順で取得。
    再訪問ユーザーへの挨拶文に過去のコンディション情報を反映するために使用。

    Returns:
        [{"daily": 3, "score": 4}, {"daily": 2, "score": 7}]
        スコアがない場合は空リスト。
    NTrH   z
            SELECT daily, condition_score 
            FROM `result` 
            WHERE session_id = %s AND condition_score IS NOT NULL
            ORDER BY daily DESC 
            LIMIT 2
        c                 0    g | ]}|d          |d         dS )re   condition_score)re   rl   r#   ).0ra   s     r   
<listcomp>z/get_recent_condition_scores.<locals>.<listcomp>.  s*    [[[sCL37H3IJJ[[[r   z-[Result DB] Recent condition scores: session=z	, scores=z/[Result DB] Get Recent Condition Scores Error: r#   )r&   r'   r(   r)   r*   r+   rL   r   r.   r/   r0   r1   )r   r3   r*   r4   rU   rQ   r6   s          r   get_recent_condition_scoresr     sk    D&==)<==-- 	sZM***  [[VZ[[[aJaaY_aabbb  	LLNNNJJLLLL		    JqJJKKK					 	LLNNNJJLLLL		  	LLNNNJJLLLL	s0   BB5 5
D?DDD DD -D=)N)NN)"__doc__mysql.connectorr&   app.core.configr   r   r)   setr   rW   r=   content_typer<   addstrboolr   intr7   r;   floatrF   listrN   dictrR   rV   rb   rd   rk   ro   r   r   r   r#   r   r   <module>r      s        1 1 1 1 1 1 1 1 $mN33  suu O OJ$ O O+ 	O 	OL$ O O  J!M!M!M|!MV!M!MNNNNO	OO&S &T & & & &$ $ $ $3 $be $ $ $ $N--!$-,/->A-KN-- - - -b>>> > 	>
 > > > > > > 	> > > >J # $    D      >!s !t ! ! ! !H* *s * *# *QT * * * *b# #    ,$# $c $c $ $ $ $Nc # c d    B. .d
 . . . .b1 1s 13 1s 1hk 1w{ 1 1 1 1h"C "D " " " " " "r   