o
    լi:                     @   s  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  q#qqqd
edefddZd5d
edededefddZd
edededededefd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 d!Zd
ededefd"d#Zd
ededefd$d%Zdedefd&d'Zd6ded(ededefd)d*Zdedefd+d,Zded-edefd.d/Zded-ed0edefd1d2ZdededB fd3d4ZdS )7u%  
==============================================================================
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                 C   s   | t v S )uD   테이블명이 48개 중 하나인지 검증 (SQL Injection 방지))VALID_TABLES)r    r   9/home/air/goalskill_t/back/app/models/goalskill_module.py_validate_table_name   s   r   
session_idoutput_textc           	   
   C   s   t | std|  d}z]zCtjjdi t}| }d|  d}|||||f |  |j	}t
d|  d| d| d|  |W W |rQ|  |  S S  tyj } zt
d	|  d
|  |d}~ww |rv|  |  w 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   r   
ValueErrormysql	connectorconnectGOALSKILL_DB_CONFIGcursorexecutecommit	lastrowidr   infoclose	Exceptionerror)	r   r   r   statusconnr&   sqlrow_ider   r   r   save_to_goalskill_table    s2   "

r3   textsource_typer.   c           
      C   s   t | std|  d}zdzJtjjdi t}| }d|  d}||||||f |  |j	}t
d|  d| d| d| d	| d
|  |W W |rX|  |  S S  tyq }	 zt
d|  d|	  |	d}	~	ww |r}|  |  w 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   r4   r5   r.   r/   r&   r0   r1   r2   r   r   r   save_to_goalskill_table_scoreG   sL   


r6   senderpart
input_text	h_scoring	s_scoring	t_scoring	p_scoring	r_scoringresult_tablec
                 C   s   d}
ziz@t jjdi t}
|
 }d}||| |||||||||	f
 |
  |j}t	d|	 d|  |W W |
rC|
  |

  S S  tyk } ztd|  W Y d}~W |
re|
  |

  dS dS d}~ww |
rw|
  |

  w 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+   r,   r-   )r   r7   r8   r9   r:   r;   r<   r=   r>   r?   r/   r&   r0   r1   r2   r   r   r   save_admin_logx   sB    

r@   c              
   C   s   t | std|  d}z[z/tjjd	i t}|jdd}d|  d}|||f | }|W W |r=|	  |	  S S  t
yh } ztd|  d|  g W  Y d}~W |rc|	  |	  S S d}~ww |rt|	  |	  w 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+   r,   r   r-   )r   r   r/   r&   r0   resultsr2   r   r   r   get_from_goalskill_table   s6   


rG   c              
   C   s   t | std|  d}z]z1tjjd	i t}|jdd}d|  d}|||f | }|p2i W W |r?|	  |	  S S  t
yj } ztd|  d|  i W  Y d}~W |re|	  |	  S S d}~ww |rv|	  |	  w w )
u8   
    특정 세션의 최신 데이터 1건 조회.
    r   NTrA   rC   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+   r,   r   r-   )r   r   r/   r&   r0   resultr2   r   r   r   get_latest_from_goalskill_table   s6   



rJ   c              
   C   s   i }d}zez<t jjdi t}|jdd}ttD ]}d| d}||| f | }|r2|||< q|W W |rA|	  |	  S S  t
yi } ztd|  i W  Y d}~W |rd|	  |	  S S d}~ww |ru|	  |	  w w )u   
    유저의 모든 Goalskill_DB 데이터를 48개 테이블에서 수집.

    Returns:
        {
            "HA_PI": [{"id": 1, "output": "..."}],
            "HA_TI": [{"id": 2, "output": 1}],
            ...
        }
    NTrA   rC   rD   z[Goalskill DB] Get All Error: r   )r"   r#   r$   r%   r&   sortedr   r'   rE   r+   r,   r   r-   )r   rI   r/   r&   r   r0   rowsr2   r   r   r   get_all_goalskill_data   s<   


rM   
goal_scopec              
   C   s:  d}d}zzct jjdi t}| }|r|gnddg}|r!|gng d}ddg}|D ].}	|D ])}
|D ]$}|	 |
 d| }d	| d
}||| f | }|rW||d 7 }q3q/q+|W W |rh|  |  S S  ty } zt	
d|  W Y d}~W |r|  |  dS dS d}~ww |r|  |  w 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'   rH   r+   r,   r   r-   )r   rN   r8   r/   totalr&   scopespartssendersspr7   r   r0   rowr2   r   r   r   get_talk_count"  sL   	

rX   c              
   C   s   d}z^z5t jjdi t}| }d}||| f | }|r*|d dur*|d ndW W |r8|  |  S S  ty` } zt	
d|  W Y d}~W |rZ|  |  dS dS d}~ww |rl|  |  w w )um   
    result テーブルから現在の最大daily番号を取得。
    行がなければ0を返す。
    Nz5SELECT MAX(daily) FROM `result` WHERE session_id = %sr   z%[Result DB] Get Current Daily Error: r   rP   )r   r/   r&   r0   rW   r2   r   r   r   get_current_dailyS  s2   

rY   dailyc           	   
   C   s&  d}zzmt jjdi t}| }d}||| |f | }|rBtd|  d| d|d   |d W W |rA|	  |	  S S d}||| d|f |
  |j}td	|  d| d|  |W W |rp|	  |	  S S  ty } z
td
|  |d}~ww |r|	  |	  w 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'   rH   r   r*   r+   r(   r)   r,   r-   )	r   rZ   r/   r&   	check_sqlexistingr0   r1   r2   r   r   r   create_result_rowi  sB    



r_   scorec              
   C   s   d}zez<t jjd	i t}| }d}|||| |f |  td| d|  d|  |j	dkW W |r?|
  |
  S S  tyg } ztd|  W Y d}~W |ra|
  |
  dS dS d}~ww |rs|
  |
  w 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   r[   r   z*[Result DB] Update Condition Score Error: Fr   )r"   r#   r$   r%   r&   r'   r(   r   r*   rowcountr+   r,   r-   )r   rZ   r`   r/   r&   r0   r2   r   r   r   update_result_condition_score  s4   

rb   c              
   C   sj  d}zz}t jjdi t}| }ddg}g }|D ]%}d| d}||| f | }|D ]}|d dur=||d  q.q|sQW W |rO|  |  dS dS t	|t
| }	tdtdt|	}
td	| d
|	dd|
  |
W W |r|  |  S S  ty } ztd|  W Y d}~W |r|  |  dS dS d}~ww |r|  |  w 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'   rE   appendr+   sumlenmaxminroundr   r*   r,   r-   )r   r/   r&   target_tables
all_scorestabler0   rL   rW   avgrI   r2   r   r   r   get_avg_condition_score  sX   


rq   )N)NN) __doc__mysql.connectorr"   app.core.configr   r   r%   setr   rN   r8   content_typer7   addstrboolr   intr3   r6   floatr@   listrG   dictrJ   rM   rX   rY   r_   rb   rq   r   r   r   r   <module>   sv    	'
1	

E"$1'!