from fastapi import APIRouter, HTTPException
from app.models import curriculum_module
from app.models.ai_curriculum_module import generate_ai_curriculum
from app.models.auth_module import _init_category_progress, _create_user_curriculum
from app.schemas.curriculum_schema import StartCurriculumRequest, ChatCurriculumRequest, GetQuizRequest, CheckQuizRequest, CheckFEQuizRequest, GenerateJournalRequest, GetJournalRequest, CertQuizRequest, CheckCertQuizRequest
from app.core.config import get_gemini_model, PPT_PATH, CURRICULUM_PDF_PATH, PROGRESS_PDF_PATH, IMG_PATH, IMG_EXP_PATH, IMG_Q_PATH
import re
from app.services.goalskill_classifier import classify_and_save
from app.models.report_db_module import get_daily_quiz_logs
from app.models.chat_log_module import save_chat_log
from google.genai import types
import json
import os
import logging
from fastapi.responses import FileResponse


logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

router = APIRouter(
    prefix="/goal-skill-t/api/curriculum",
    tags=["Curriculum"]
)
file_router = APIRouter(
    prefix="/goal-skill-t/api/file",
    tags=["Files"]
)

# 진행 버튼 sentinel 토큰 (프론트 진행 버튼 클릭 시에만 전송)
# 자유 텍스트 입력으로는 절대 진행되지 않도록 차단
PROGRESS_TOKEN = "__USER_PROGRESS_CONFIRMED__"


def _tobu_free_chat_in_step(client, user_message: str, context_label: str, button_label: str) -> str:
    """학습 진행 단계(영상/PPT/이론) 중 자유 텍스트 입력 → Tobu 친구 톤 자유 응답.
    사용자 의도에 따라 진행 안내 여부를 분기. 진행 자체는 트리거하지 않음."""
    prompt = f"""
あなたは学習者の親しい友人「Tobu」です。タメ口、絵文字OK、明るく短く。

# 現在の状況
ユーザーは「{context_label}」の学習中。学習画面に「{button_label}」というボタンがあり、それを押すと次のステップに進む仕組み。

# ユーザーの発言
"{user_message}"

# 返し方ルール
1. **学習内容の質問**（「if文って何？」「これどういう意味？」など）
   → 質問に短く答える。最後は「分かったかな？まだ見てる途中ならゆっくり見てね」程度。
   → **進行を急かさない。ボタンを押すよう促さない。**
2. **「見た」「終わった」「次行こう」など進行の意思表示**
   → 「OK！じゃあ『{button_label}』ボタン押してね」と案内する。
3. **雑談・愚痴・一言反応**（「うーん」「むずい」など）
   → 軽く受け止める。ボタン案内は省略してよい。

# 表記ルール
- ボタン名を引用するときは「{button_label}」のように、二重引用符『』ではなく必ず一重「」だけを使う。
- 重ねた引用（『「」』のような表記）は絶対に禁止。

# 出力
- 全体3行以内、短く。
- 学習者のペースを尊重し、進行を強要しない。
"""
    response = client.models.generate_content(
        model="gemini-2.5-flash",
        contents=[types.Content(role="user", parts=[types.Part(text=prompt)])]
    )
    return response.text


SYSTEM_PROMPT = """
あなたは学習者の「親しい友人（Best Friend）」です。
以下のルールを絶対に守ってください：
1. **言語**: 日本語のみ使用。
2. **口調**: 絶対に敬語（〜です、〜ます）を使わないこと。「〜だよ」「〜じゃん」「〜だね」といった、仲の良い友達と話す「タメ口」を使うこと。
3. **態度**: 明るく、ポジティブに、絵文字（🔥, ✨, 💪, 😂など）を多用して会話すること。
4. **役割**: 先生ではなく、一緒に走るパートナーとして振る舞うこと。
"""


#get_user_progress = 유저의 현재 일차 확인
#get_previous_feedback = 유저의 디버그 일지 확인
#get_today_item_info = 오늘(N일차)의 커리큘럼 아이템 정보 조회 (user_curriculum + master_items)

@router.post("/start")
async def start_curriculum(request: StartCurriculumRequest):
    try:
        session_id = request.session_id
        
        # 1. 진도 확인 (기존 로직 유지)
        progress = curriculum_module.get_user_progress(session_id) # 1/2 이렇게 데이터가 들어감
        if not progress:
             return {"status": "error", "message": "進捗データが見つかりません。"}
        
        current_day = progress['current_day']
        status = progress['status']
        
        #  오늘치 커리큘럼이 user_curriculum에 없으면 자동 배정 (1~2개만)
        curriculum_module.init_user_curriculum(session_id, current_day)
        
        # 0(진행중)이 아니면 시작 안 함 (status는 varchar이므로 문자열 비교)
        if str(status) not in ('0', 'NOT_STARTED'):
            return {"status": "completed", "message": "本日の学習は既に完了しています。"}

        # 2. 데이터 조회 (기존 로직 유지)
        prev_data = curriculum_module.get_previous_feedback(session_id, current_day)
        today_item = curriculum_module.get_today_item_info(session_id, current_day)
        
        if not today_item:
             return {"status": "error", "message": "本日のカリキュラムが見つかりません。"}

        # 3. 프롬프트 구성 [수정됨]
        item_name = today_item['name']
        prev_summary = prev_data['summary_content'] if prev_data else "なし"
        prev_feedback = prev_data['ai_feedback'] if prev_data else "なし"
        prev_praise = prev_data['praise_content'] if prev_data else "なし"
        
        # ★ 여기가 핵심 수정 부분입니다 ★
        prompt = f"""
            あなたは学習者（親しい友人）のパートナーです。
            今日は学習 **Day {current_day}** です。
            今日のテーマは「**{item_name}**」です。
            
            [昨日の振り返り]
            - 学習内容: {prev_summary}
            - AIフィードバック: {prev_feedback}
            - 称賛: {prev_praise}
            
            これらを踏まえて、今日の学習を始めるユーザーに挨拶をしてください。
            
            【絶対ルール - 厳守すること】
            1. **分割出力**: 発言を短く切り、2〜3つの吹き出しに分けるため、文の区切りに「|||」を入れてください。
               (例: おっす！久しぶり！|||今日はこのテーマだね。|||準備はいい？)
            2. **短文**: 1つの吹き出しは短く、テンポよく。長文は禁止。
            3. **強調**: 重要な単語（Day数やテーマ名）は **太字** (例: **Day {current_day}**) にして。
            4. **トーン**: 敬語禁止。親友のように明るく、絵文字を使って。
            5. **内容**: 昨日の頑張りを一言褒めて、今日のテーマの面白さを伝えて、最後に「準備はいい？」と聞く。
            """
        
        client = get_gemini_model()
        
        # (기존 코드 유지)
        response = client.models.generate_content(
            model="gemini-2.5-flash",
            contents=[types.Content(role="user", parts=[types.Part(text=prompt)])],
            config=types.GenerateContentConfig(
                system_instruction=SYSTEM_PROMPT,
                temperature=0.8 # 창의성 약간 높임
            )
        )
        
        # Goalskill 분류: Part C, AI 시작 인사
        await classify_and_save(session_id=session_id, sender="I", part="C", text=response.text)
        save_chat_log(session_id=session_id, sender="I", category="curriculum", log=response.text)

        return {
            "status": "start",
            "message": response.text,
            "current_day": current_day,
            "item_id": today_item['item_id']
        }

    except Exception as e:
        logger.error(f"Start Error: {e}") # 로깅 추가
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/chat")
async def chat_curriculum(request: ChatCurriculumRequest):
    try:
        client = get_gemini_model()
        
        # 1. 시작 단계 (긍정/부정 판별)
        if request.current_step == 'START':
            # Goalskill 분류: Part C, User 메시지 (START)
            await classify_and_save(session_id=request.session_id, sender="M", part="C", text=request.user_message)
            save_chat_log(session_id=request.session_id, sender="M", category="curriculum", log=request.user_message)

            prompt = f"""
            ユーザーの発言: "{request.user_message}"
            
            この発言が「ポジティブ(やる気がある)」か「ネガティブ(やる気がない・不安)」か判定してください。
            
            もし「ネガティブ」なら、「目標を達成するためには、今やるしかない！」というニュアンスの厳しめの応援メッセージを作成してください。
            もし「ポジティブ」なら、「その意気だ！必ず目標は達成できる！」というニュアンスの強い称賛メッセージを作成してください。
            
            出力フォーマット(JSON):
            {{
                "sentiment": "POSITIVE" or "NEGATIVE",
                "message": "作成したメッセージ"
            }}
            """
            response = client.models.generate_content(
                model="gemini-2.5-flash",
                contents=[types.Content(role="user", parts=[types.Part(text=prompt)])],
                config={"response_mime_type": "application/json"}
            )
            result_data = json.loads(response.text)
            # Goalskill 분류: Part C, AI 응답 (START)
            await classify_and_save(session_id=request.session_id, sender="I", part="C", text=result_data.get("message", ""))
            save_chat_log(session_id=request.session_id, sender="bot", category="curriculum", log=result_data.get("message", ""))
            return result_data

        # 2. 유튜브 완료 확인 — 진행 버튼 클릭(토큰)으로만 진행. 자유 텍스트는 진행 X
        elif request.current_step == 'YOUTUBE':
            is_button_click = request.user_message.strip() == PROGRESS_TOKEN
            log_text = "[ボタン] 動画を見終わった" if is_button_click else request.user_message

            await classify_and_save(session_id=request.session_id, sender="M", part="C", text=log_text)
            save_chat_log(session_id=request.session_id, sender="user", category="curriculum", log=log_text)

            if not is_button_click:
                chat_msg = _tobu_free_chat_in_step(client, request.user_message, "YouTube動画", "動画を見終わった")
                save_chat_log(session_id=request.session_id, sender="bot", category="curriculum", log=chat_msg)
                return {"is_finished": False, "message": chat_msg}

            session_id = request.session_id

            # =================================================================
            # [수정] item_id가 None일 경우, DB에서 현재 진도를 조회하여 자동 탐지
            # =================================================================
            target_item_id = request.item_id

            if target_item_id is None:
                print("!!! item_id is Missing -> Auto-detecting from Progress !!!")
                # 1. 현재 몇 일차인지 확인
                progress = curriculum_module.get_user_progress(session_id)
                if progress:
                    current_day = progress['current_day']
                    # 2. 해당 날짜의 대표 아이템 ID 하나만 가져오기
                    today_info = curriculum_module.get_today_item_info(session_id, current_day)
                    if today_info:
                        target_item_id = today_info['item_id']
                        print(f"   -> Auto-detected item_id: {target_item_id}")

            # =================================================================
            # 1. 데이터 조회 (탐지된 target_item_id 사용)
            # =================================================================
            if target_item_id:
                daily_items, _ = curriculum_module.get_daily_items_and_resources(session_id, target_item_id)
            else:
                daily_items = [] # 여전히 못 찾았으면 빈 리스트

            print(f"============== [DEBUG LOG] ==============")
            print(f"1. Target item_id: {target_item_id}")
            print(f"2. Daily Items Found: {len(daily_items) if daily_items else 0}")

            # [수정] PPT를 learning_resources DB에서 조회 (파일시스템 직접 검색 → DB 조회)
            valid_ppts = []
            valid_item_names = []

            if daily_items:
                item_ids = [item['item_id'] for item in daily_items]
                ppt_resources = curriculum_module.get_ppt_resources(item_ids)

                for ppt in ppt_resources:
                    file_name = ppt['url']  # learning_resources.url에 파일명 저장됨
                    viewer_url = f"components/ppt_viewer.html?file={file_name}"

                    print(f"3. PPT from DB: {file_name} -> {viewer_url}")

                    valid_ppts.append({
                        "item_id": ppt['item_id'],
                        "name": ppt['title'],
                        "url": viewer_url
                    })
                    valid_item_names.append(ppt['title'])

            print(f"=========================================")

            # =================================================================
            # 2. AI 프롬프트 구성
            # =================================================================
            if not valid_ppts:
                # PPT가 하나도 없으면 바로 퀴즈로 넘어가거나 안내
                return {"is_finished": True, "message": "今回はPPT資料はないみたい！次はクイズに進もうか！", "ppts": []}

            ppt_topic_str = "」と「".join(valid_item_names)

            ppt_prompt = f"""
            状況: 親しい友人（Best Friend）です。
            タスク: 学習内容「{ppt_topic_str}」のPPT資料（計{len(valid_ppts)}つ）を渡します。

            [制約]
            1. **超短文**: 「これまとめたPPT作ったから見てみて！」くらい短く。
            2. URL禁止。
            """
            ppt_msg_response = client.models.generate_content(
                model="gemini-2.5-flash",
                contents=[types.Content(role="user", parts=[types.Part(text=ppt_prompt)])]
            )

            return {
                "is_finished": True,
                "message": ppt_msg_response.text,
                "ppts": valid_ppts
            }
        elif request.current_step == 'PPT':
            # 진행 버튼 클릭(토큰)으로만 진행. 자유 텍스트는 진행 X
            is_button_click = request.user_message.strip() == PROGRESS_TOKEN
            log_text = "[ボタン] PPTを見終わった" if is_button_click else request.user_message

            await classify_and_save(session_id=request.session_id, sender="M", part="C", text=log_text)
            save_chat_log(session_id=request.session_id, sender="user", category="curriculum", log=log_text)

            if not is_button_click:
                chat_msg = _tobu_free_chat_in_step(client, request.user_message, "PPT資料", "PPTを見終わった")
                save_chat_log(session_id=request.session_id, sender="bot", category="curriculum", log=chat_msg)
                return {"is_finished": False, "message": chat_msg}

            quiz_prompt = f"""
            あなたはユーザーの親しい友人（Best Friend）です。
            ユーザーがPPT学習を終えました。次は「実践クイズ（IT問題）」です。

            [メッセージ作成ルール - 厳守]
            1. **超短文**: ダラダラ話さない。「インプット完了！次はアウトプットだ！」くらいのスピード感で。
            2. **分割**: 文章を2〜3つの短い吹き出しに分け、間に「|||」を入れる。
            3. **強調**: 「**クイズ**」や「**実践**」などの単語は太字にする。
            4. **内容**: 失敗を恐れずに挑戦しよう、というポジティブなメッセージを短く。

            例:
            PPTお疲れ！インプットはバッチリだね！|||
            じゃあ次は、**実践クイズ**で腕試ししてみようか！|||
            間違えても大丈夫！**アウトプット**が大事だからね！
            """
            quiz_msg_response = client.models.generate_content(
                model="gemini-2.5-flash",
                contents=[types.Content(role="user", parts=[types.Part(text=quiz_prompt)])]
            )
            return {"is_finished": True, "message": quiz_msg_response.text}

        # =========================================================
        # THEORY 단계: 진행 버튼 클릭(토큰)으로만 진행. 자유 텍스트는 진행 X
        # 정상 경로는 프론트 모달의 "次" 버튼 → finishFEPhase 직접 호출이며,
        # 이 분기는 채팅창 입력으로 우회 진행되는 것을 차단하기 위함.
        # =========================================================
        elif request.current_step == 'THEORY':
            is_button_click = request.user_message.strip() == PROGRESS_TOKEN
            log_text = "[ボタン] 理論学習を見終わった" if is_button_click else request.user_message

            await classify_and_save(session_id=request.session_id, sender="M", part="C", text=log_text)
            save_chat_log(session_id=request.session_id, sender="user", category="curriculum", log=log_text)

            if not is_button_click:
                chat_msg = _tobu_free_chat_in_step(client, request.user_message, "資格試験の理論学習", "学習モーダル内の次")
                save_chat_log(session_id=request.session_id, sender="bot", category="curriculum", log=chat_msg)
                return {"is_finished": False, "message": chat_msg}

            fe_intro_prompt = f"""
            あなたはユーザーの親しい友人（Best Friend）です。
            ユーザーが資格試験の理論学習を終えました。次は「基本情報技術者試験の練習問題」です。

            [メッセージ作成ルール - 厳守]
            1. **超短文**: ダラダラ話さない。「理論バッチリ！次は問題だ！」くらいのスピード感で。
            2. **分割**: 文章を2〜3つの短い吹き出しに分け、間に「|||」を入れる。
            3. **強調**: 「**基本情報**」や「**実力試し**」などの単語は太字にする。
            4. **内容**: 理論学習を褒めて、次のFE問題へ誘導する。

            例:
            理論学習お疲れ！頭に入ったかな？|||
            じゃあ次は、**基本情報技術者試験**の問題に挑戦してみようか！|||
            学んだ知識が通用するか、**実力試し**だ！
            """
            fe_msg_response = client.models.generate_content(
                model="gemini-2.5-flash",
                contents=[types.Content(role="user", parts=[types.Part(text=fe_intro_prompt)])]
            )
            return {"is_finished": True, "message": fe_msg_response.text}

        else:
            # 퀴즈 중이거나 알 수 없는 단계에서 사용자가 일반 질문을 한 경우 (일반 채팅 폴백)
            await classify_and_save(session_id=request.session_id, sender="M", part="C", text=request.user_message)
            save_chat_log(session_id=request.session_id, sender="user", category="curriculum", log=request.user_message)

            prompt_fallback = f"""
            ユーザーの発言: "{request.user_message}"
            あなたはプログラミングやITの学習をサポートする親しい友人（Best Friend）です。
            ユーザーが学習中（クイズや理論の最中）に質問やコメントをしました。
            
            [タスク]
            1. 質問であれば、わかりやすく簡潔に答えてください。
            2. ただの呟きであれば、共感して応援してください。
            3. タメ口で、親身になって明るく答えること。
            
            必ず以下のJSON形式で返してください:
            {{
                "is_finished": false,
                "message": "作成したメッセージ"
            }}
            """
            response = client.models.generate_content(
                model="gemini-2.5-flash",
                contents=[types.Content(role="user", parts=[types.Part(text=prompt_fallback)])],
                config={"response_mime_type": "application/json"}
            )
            result = json.loads(response.text)
            await classify_and_save(session_id=request.session_id, sender="I", part="C", text=result.get("message", ""))
            save_chat_log(session_id=request.session_id, sender="bot", category="curriculum", log=result.get("message", ""))
            return result

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/resources")
async def get_resources(request: GetQuizRequest):
    try:
        session_id = request.session_id
        
        daily_items, resources = curriculum_module.get_daily_items_and_resources(session_id, request.item_id)
        
        if not daily_items:
             raise HTTPException(status_code=404, detail="Schedule not found")

        topic_names = "」と「".join([item['name'] for item in daily_items])
        
        logger.info(f"Today's Topics: {topic_names}")
        logger.info(f"Total Resources Found: {len(resources)}")

        client = get_gemini_model()
        
        # [수정] 프롬프트: 인사 금지 + 분할 출력( ||| ) + 강조( ** )
        intro_prompt = f"""
        状況: 親しい友人（Best Friend）です。直前の挨拶は済み。
        今日のテーマ「{topic_names}」の動画（{len(resources)}本）を紹介してください。

        [制約事項 - 厳守]
        1. **挨拶禁止**: 「おはよう」などは不可。いきなり本題へ。
        2. **超短文・簡潔**: 
           - ダラダラ説明しない。**1つの吹き出しにつき1〜2文**で短く切る。
           - 「これめっちゃ分かりやすいよ！」「〇〇の仕組みがバッチリ分かるはず！」程度でOK。
        3. **分割出力**: 「|||」で区切って2〜3つに分ける。
        4. **強調**: キーワード（「条件分岐」など）は **太字**。
        5. **URL禁止**。
        """

        intro_msg_response = client.models.generate_content(
            model="gemini-2.5-flash",
            contents=[types.Content(role="user", parts=[types.Part(text=intro_prompt)])]
        )
        
        return {
            "message": intro_msg_response.text,
            "resources": resources
        }

    except Exception as e:
        logger.error(str(e))
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/ppts")
async def get_ppts_endpoint(request: GetQuizRequest):
    try:
        session_id = request.session_id
        target_item_id = request.item_id
        
        if target_item_id is None:
            progress = curriculum_module.get_user_progress(session_id)
            if progress:
                current_day = progress['current_day']
                today_info = curriculum_module.get_today_item_info(session_id, current_day)
                if today_info:
                    target_item_id = today_info['item_id']

        daily_items, _ = curriculum_module.get_daily_items_and_resources(session_id, target_item_id)
        if not daily_items:
             raise HTTPException(status_code=404, detail="Schedule not found")

        item_ids = [item['item_id'] for item in daily_items]
        ppt_resources = curriculum_module.get_ppt_resources(item_ids)
        
        valid_ppts = []
        for ppt in ppt_resources:
            file_name = ppt['url']
            viewer_url = f"components/ppt_viewer.html?file={file_name}"
            valid_ppts.append({
                "item_id": ppt['item_id'],
                "name": ppt['title'],
                "url": viewer_url 
            })
            
        return {"ppts": valid_ppts}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/quiz")
async def get_quiz(request: GetQuizRequest):
    try:
        # 1. 먼저 요청받은 item_id (예: 17번)로 문제를 찾아봅니다.
        problem = curriculum_module.get_quiz_problem(request.item_id, request.q_num)
        
        # 2. 만약 없다면? 같은 날짜(Day)의 다른 아이템들도 뒤져봅니다. (예: 18번)
        if not problem:
             # 오늘 배울 아이템들을 싹 가져옵니다 (17번, 18번...)
             daily_items, _ = curriculum_module.get_daily_items_and_resources(request.session_id, request.item_id)
             
             if daily_items:
                 for item in daily_items:
                     # 이미 확인한 17번은 건너뛰고
                     if item['item_id'] == request.item_id:
                         continue
                     
                     # 다른 아이템(18번)으로 문제를 다시 조회해봅니다.
                     problem = curriculum_module.get_quiz_problem(item['item_id'], request.q_num)
                     if problem:
                         # 찾았다! (반복 종료)
                         break
        
        # 그래도 없으면 진짜 없는 것
        if not problem:
             raise HTTPException(status_code=404, detail="問題が見つかりません。")
             
        return problem

    except HTTPException as he:
        # 404 같은 HTTP 에러는 그대로 내보냅니다 (500으로 감싸지 않음)
        raise he
    except Exception as e:
        # 진짜 서버 에러만 500으로 처리
        logger.error(f"Quiz Error: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/quiz/check")
async def check_quiz(request: CheckQuizRequest):
    try:
        client = get_gemini_model()
        
        # [수정] 프롬프트 강화: 정답과 해설을 기준점(Ground Truth)으로 제공
        prompt = f"""
        あなたはプログラミング学習の採点官であり、ユーザーの親しい友人です。
        
        [問題]
        {request.question_text}
        
        [正解データ]
        {request.correct_answer}
        
        [解説データ]
        {request.explanation}
        
        [ユーザーの回答]
        {request.user_answer}
        
        [タスク]
        ユーザーの回答が「正解データ」と一致しているか、あるいは意味的に正しいかを判定してください。
        解説データの内容を参考にして、なぜそうなるのかを補足してください。
        
        [出力ルール]
        1. 正解の場合: 「正解！さすがだね！」と褒めて、簡単に解説。
        2. 不正解の場合: 「惜しい！不正解だよ」と励まし、[解説データ]を元に正しい答えを教えてあげる。
        3. C#やJavaなどの別言語の話は絶対にしないこと。今はPythonの学習中。
        4. 口調はタメ口で。
        5. **箇条書き禁止**: 「・」「-」「*」などのリスト記号は絶対に使わないこと。すべて普通の文章（段落）で書くこと。
        """
        
        response = client.models.generate_content(
            model="gemini-2.5-flash",
            contents=[types.Content(role="user", parts=[types.Part(text=prompt)])]
        )
        
        # Goalskill 분류: session_id가 있으면 실행
        if request.session_id:
            await classify_and_save(session_id=request.session_id, sender="M", part="C", text=request.user_answer)
            save_chat_log(session_id=request.session_id, sender="user", category="quiz", log=request.user_answer)
            await classify_and_save(session_id=request.session_id, sender="I", part="C", text=response.text)
            save_chat_log(session_id=request.session_id, sender="bot", category="quiz", log=response.text)

            # 파이썬 퀴즈 결과 저장
            if request.problem_id:
                is_correct = "正解" in response.text or "さすが" in response.text
                conn_a = None
                try:
                    from app.models.curriculum_module import A_DB_CONFIG
                    import mysql.connector
                    conn_a = mysql.connector.connect(**A_DB_CONFIG)
                    cursor_a = conn_a.cursor()
                    sql_insert = """
                        INSERT INTO quiz_results (session_id, problem_id, is_correct, user_answer)
                        VALUES (%s, %s, %s, %s)
                    """
                    cursor_a.execute(sql_insert, (request.session_id, request.problem_id, is_correct, request.user_answer))
                    conn_a.commit()
                except Exception as e:
                    logger.error(f"Save quiz_results error: {e}")
                finally:
                    if conn_a:
                        conn_a.close()
        
        return {"result_message": response.text}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
    

@file_router.get("/ppt/{file_name}")
async def get_ppt_file(file_name: str):
    """
    프론트엔드 URL: /goal-skill-t/api/file/ppt/item_18.pptx
    실제 서버 경로: /home/air/goalskill_t/back/PPT/item_18.pptx
    """
    # 1. 실제 파일이 있는 서버 내부 경로
    base_dir = PPT_PATH
    file_path = os.path.join(base_dir, file_name)
    
    # 2. 파일이 진짜 있는지 확인하고 전송
    if os.path.exists(file_path):
        return FileResponse(
            path=file_path, 
            filename=file_name, 
            # 브라우저가 PPT임을 알 수 있게 미디어 타입 지정
            media_type='application/vnd.openxmlformats-officedocument.presentationml.presentation'
        )
    else:
        # 파일이 없으면 404 에러
        raise HTTPException(status_code=404, detail="File not found on server")

@router.get("/ppt/slides/{file_name}")
async def get_ppt_slides(file_name: str):
    """PPTXファイルのスライド内容をJSON形式で返すAPI"""
    from pptx import Presentation
    from pptx.util import Inches, Pt, Emu
    from pptx.dml.color import RGBColor
    
    file_path = os.path.join(PPT_PATH, file_name)
    if not os.path.exists(file_path):
        raise HTTPException(status_code=404, detail="PPT file not found")
    
    try:
        prs = Presentation(file_path)
        slides_data = []
        
        # スライドサイズ取得
        slide_width = prs.slide_width
        slide_height = prs.slide_height
        
        for slide_idx, slide in enumerate(prs.slides):
            slide_info = {"slide_num": slide_idx + 1, "elements": []}
            
            for shape in slide.shapes:
                element = {"type": "unknown"}
                
                if shape.has_text_frame:
                    paragraphs = []
                    for para in shape.text_frame.paragraphs:
                        runs = []
                        for run in para.runs:
                            run_data = {"text": run.text}
                            if run.font.bold:
                                run_data["bold"] = True
                            if run.font.size:
                                run_data["fontSize"] = run.font.size.pt
                            if run.font.color and run.font.color.rgb:
                                run_data["color"] = str(run.font.color.rgb)
                            runs.append(run_data)
                        
                        if runs or para.text.strip():
                            para_data = {"runs": runs, "text": para.text}
                            if para.alignment is not None:
                                para_data["align"] = str(para.alignment)
                            paragraphs.append(para_data)
                    
                    element = {
                        "type": "text",
                        "paragraphs": paragraphs,
                        "left": shape.left / slide_width * 100 if shape.left else 0,
                        "top": shape.top / slide_height * 100 if shape.top else 0,
                        "width": shape.width / slide_width * 100 if shape.width else 100,
                        "height": shape.height / slide_height * 100 if shape.height else 10,
                    }
                
                elif shape.has_table:
                    table_data = []
                    for row in shape.table.rows:
                        cells = [cell.text for cell in row.cells]
                        table_data.append(cells)
                    element = {"type": "table", "rows": table_data}
                
                if element["type"] != "unknown":
                    slide_info["elements"].append(element)
            
            slides_data.append(slide_info)
        
        return {
            "file": file_name,
            "total_slides": len(slides_data),
            "slides": slides_data
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"PPT parse error: {str(e)}")

# =========================================================
# 자격증 이론 API
# =========================================================
@router.post("/theory/data")
async def get_theory(request: StartCurriculumRequest):
    """현재 일차의 CERT 아이템에 맞는 이론/문제 데이터를 조회"""
    try:
        session_id = request.session_id
        
        # 1. 유저의 현재 일차 조회
        progress = curriculum_module.get_user_progress(session_id)
        if not progress:
            raise HTTPException(status_code=404, detail="Progress not found")
        
        current_day = progress['current_day']
        
        # 2. 해당 일차의 CERT 아이템 조회 (THEORY/PRACTICE 모두)
        cert_item = curriculum_module.get_cert_item_for_day(session_id, current_day)
        
        if not cert_item:
            # CERT 아이템 없음 → 13~20일차(sort_order 13 이상)인 경우에만 복습 모드 발동
            sort_order = ((current_day - 1) % 20) + 1
            if sort_order >= 13:
                chapters = curriculum_module.get_cert_chapters_for_month(session_id, current_day)
                if chapters:
                    return {"found": False, "review_mode": True, "chapters": chapters}
            return {"found": False, "message": "今日は資格試験の学習はないよ！"}
        
        # 3. CERT 아이템 이름에서 챕터 번호 추출 ("第1章 ..." → 1)
        match = re.search(r'第(\d+)章', cert_item['name'])
        if not match:
            return {"found": False, "message": "チャプター情報が見つかりません。"}
        
        section_num = int(match.group(1))
        item_type = cert_item['item_type']  # 'THEORY' or 'PRACTICE'
        
        # 4. PRACTICE일 → 이론 없이 퀴즈만
        if item_type == 'PRACTICE':
            return {
                "found": True,
                "practice_only": True,
                "cert_name": cert_item['name'],
                "section": section_num
            }
        
        # 5. THEORY일 → Theory_DB에서 이론 데이터 조회
        #    item_id가 THEORY_SUB_RANGES에 있으면 서브챕터 범위 필터링 적용
        sub_range = curriculum_module.THEORY_SUB_RANGES.get(cert_item['item_id'])
        theory_items = curriculum_module.get_theory_data(section_num, sub_range=sub_range)
        
        if not theory_items:
            return {"found": False, "message": "理論データが見つかりません。"}
        
        # 6. 이미지 경로를 API URL로 변환
        for item in theory_items:
            if item.get('img') and item['img']:
                img_filename = os.path.basename(item['img'])
                item['img'] = f"/goal-skill-t/api/file/theory-img/section{section_num}/{img_filename}"
        
        # 7. 챕터별로 그룹핑
        chapters = {}
        for item in theory_items:
            ch = item['chapter']
            if ch not in chapters:
                chapters[ch] = {
                    'chapter': ch,
                    'main_title': item['main_title'],
                    'items': []
                }
            chapters[ch]['items'].append(item)
        
        return {
            "found": True,
            "practice_only": False,
            "cert_name": cert_item['name'],
            "section": section_num,
            "chapters": list(chapters.values()),
            "total_items": len(theory_items)
        }
        
    except HTTPException as he:
        raise he
    except Exception as e:
        logger.error(f"Theory Data Error: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/cert/review/chapters")
async def get_review_chapters(request: StartCurriculumRequest):
    """13~20일차 복습 모드: 해당 월에 배운 장 목록 반환"""
    try:
        session_id = request.session_id
        progress = curriculum_module.get_user_progress(session_id)
        if not progress:
            raise HTTPException(status_code=404, detail="Progress not found")
        
        chapters = curriculum_module.get_cert_chapters_for_month(session_id, progress['current_day'])
        return {"chapters": chapters}
    except Exception as e:
        logger.error(f"Review Chapters Error: {e}")
        raise HTTPException(status_code=500, detail=str(e))

from pydantic import BaseModel
class TheoryIntroRequest(BaseModel):
    cert_name: str

@router.post("/theory/intro")
async def get_theory_intro(request: TheoryIntroRequest):
    """자격증 이론 소개 메시지를 AI로 생성"""
    try:
        client = get_gemini_model()
        prompt = f"""
        あなたはユーザーの親しい友人（Best Friend）です。
        ユーザーが実践クイズを終え、次は資格試験の理論学習「{request.cert_name}」に入ります。

        [メッセージ作成ルール - 厳守]
        1. **超短文**: 2〜3つの短い吹き出しに分け、間に「|||」を入れる。
        2. **強調**: 「**資格試験**」「**理論学習**」「**{request.cert_name}**」などの重要ワードは**太字**にする。
        3. **口調**: 敬語禁止。タメ口で明るく。絵文字1〜2個使用。
        4. **内容**: クイズお疲れ → 次は理論学習だよ → チャプター名を紹介。
        5. **絶対に4つ以上の吹き出しにしない**。3つまで。

        例:
        クイズお疲れ！💪|||次は、**資格試験の理論学習**だよ！|||「**{request.cert_name}**」の内容を確認しよう！
        """
        response = client.models.generate_content(
            model="gemini-2.5-flash",
            contents=[types.Content(role="user", parts=[types.Part(text=prompt)])]
        )
        return {"message": response.text}
    except Exception as e:
        logger.error(f"Theory Intro Error: {e}")
        return {"message": f"クイズお疲れ！💪✨|||次は、**資格試験の理論学習**だよ！|||「**{request.cert_name}**」の内容を確認しよう！"}

@router.get("/theory/section/{section_num}")
async def get_theory_section(section_num: int):
    """섹션 번호로 직접 이론 데이터 조회 (복습 모드용)"""
    try:
        theory_items = curriculum_module.get_theory_data(section_num)
        if not theory_items:
            raise HTTPException(status_code=404, detail="Theory data not found")
        
        # 이미지 경로 변환
        for item in theory_items:
            if item.get('img') and item['img']:
                img_filename = os.path.basename(item['img'])
                item['img'] = f"/goal-skill-t/api/file/theory-img/section{section_num}/{img_filename}"
        
        # 챕터별 그룹핑
        chapters = {}
        for item in theory_items:
            ch = item['chapter']
            if ch not in chapters:
                chapters[ch] = {'chapter': ch, 'main_title': item['main_title'], 'items': []}
            chapters[ch]['items'].append(item)
        
        return {
            "found": True,
            "section": section_num,
            "chapters": list(chapters.values()),
            "total_items": len(theory_items)
        }
    except HTTPException as he:
        raise he
    except Exception as e:
        logger.error(f"Theory Section Error: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@file_router.get("/theory-img/{section}/{filename}")
async def get_theory_image(section: str, filename: str):
    """이론 이미지 파일 서빙"""
    file_path = os.path.join(IMG_PATH, section, filename)
    
    if os.path.exists(file_path):
        return FileResponse(path=file_path, media_type='image/png')
    else:
        raise HTTPException(status_code=404, detail="Image not found")
    
@router.post("/fe/intro")
async def get_fe_intro():
    try:
        client = get_gemini_model()
        # [수정] FE 소개 메시지
        # 요청: "간결하고 짧게, 진하게 강조, 1~3개 말풍선( ||| )"
        prompt = """
        あなたはユーザーの親しい友人です。
        ユーザーがPythonの課題をクリアしました。次は「基本情報技術者試験」の練習問題です。
        
        以下のルールでメッセージを作成してください：
        1. **分割**: 文章を2〜3つの短いフレーズに分け、間に「|||」を入れる。
        2. **短文**: 1つの吹き出しは短く簡潔に。「次はこれだ！」というスピード感で。
        3. **強調**: 「**基本情報**」や「**実力試し**」などは太字にする。
        4. **内容**: Pythonクリアを褒めて、次のFE問題へ誘導する。
        
        例:
        お疲れ！Python完走だね！さすが！|||
        じゃあ次は、**基本情報技術者試験**の問題に挑戦してみようか！|||
        学んだ知識が通用するか、**実力試し**だ！
        """
        response = client.models.generate_content(
            model="gemini-2.5-flash",
            contents=[types.Content(role="user", parts=[types.Part(text=prompt)])]
        )
        return {"message": response.text}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

# 2. FE 문제 조회
@router.post("/fe/quiz")
async def get_fe_quiz(request: GetQuizRequest): # item_id 등은 무시하고 q_num만 사용
    try:
        # DB 모듈에서 총 개수와 문제 상세 정보 조회
        total_count = curriculum_module.get_fe_problem_count()
        problem = curriculum_module.get_fe_problem_detail(request.q_num)
        
        if not problem:
             raise HTTPException(status_code=404, detail="問題が見つかりません。")
        
        # 마지막 문제인지 확인 (q_num이 전체 개수보다 크거나 같으면 마지막)
        problem['is_last'] = (request.q_num >= total_count)
        
        return problem
    except Exception as e:
        logger.error(str(e))
        raise HTTPException(status_code=500, detail=str(e))

# 3. FE 정답 확인
@router.post("/fe/quiz/check")
async def check_fe_quiz(request: CheckFEQuizRequest):
    try:
        # DB 모듈을 통해 정답 비교 및 해설 가져오기
        result = curriculum_module.check_fe_answer_logic(request.question_number, request.user_answer)
        return result
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

# ===== cert_questions 기반 FE 퀴즈 (챕터별 동적) =====
@router.post("/cert/quiz")
async def get_cert_quiz(request: CertQuizRequest):
    """챕터별 cert_questions 문제 조회"""
    try:
        total_count = curriculum_module.get_cert_question_count(request.chapter)
        problem = curriculum_module.get_cert_question_detail(request.chapter, request.q_num)
        
        if not problem:
            raise HTTPException(status_code=404, detail="問題が見つかりません。")
        
        problem['is_last'] = (request.q_num >= total_count)
        problem['total_count'] = total_count
        
        # question_img 경로 변환
        section_dir = f"section{request.chapter}"

        def _to_cert_img_url(value: str) -> str:
            if not value:
                return value
            v = value.strip()
            lower = v.lower()
            is_img = lower.endswith(('.png', '.jpg', '.jpeg', '.gif', '.webp'))
            looks_like_path = v.startswith('/') or '\\' in v or '/img_q/' in v or '/img_explanation/' in v
            if is_img or looks_like_path:
                filename = v.replace('\\', '/').split('/')[-1]
                return f"/goal-skill-t/api/file/cert-img/{section_dir}/{filename}"
            return value

        if problem.get('question_img'):
            problem['question_img'] = _to_cert_img_url(problem['question_img'])

        # 선택지(option_1~4)도 이미지 경로면 cert-img URL 로 변환
        if isinstance(problem.get('choices'), dict):
            for key in ('one', 'two', 'three', 'four'):
                problem['choices'][key] = _to_cert_img_url(problem['choices'].get(key) or "")

        return problem
    except HTTPException as he:
        raise he
    except Exception as e:
        logger.error(f"cert quiz error: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/cert/quiz/check")
async def check_cert_quiz(request: CheckCertQuizRequest):
    """cert_questions 정답 확인 + 해설"""
    try:
        result = curriculum_module.check_cert_answer(request.chapter, request.question_number, request.user_answer, request.session_id)
        
        # solution_img 경로 변환
        if result.get('explanation_type') == 'img' and result.get('explanation'):
            filename = result['explanation'].split('/')[-1]
            section_dir = f"section{request.chapter}"
            result['explanation'] = f"/goal-skill-t/api/file/cert-img/{section_dir}/{filename}"
            
        if request.session_id:
            user_msg = f"[資格問題 {request.question_number}] ユーザー回答: {request.user_answer}"
            bot_msg = f"正解: {result['correct_answer']} (判定: {'正解' if result['is_correct'] else '不正解'})"
            save_chat_log(session_id=request.session_id, sender="user", category="cert_quiz", log=user_msg)
            save_chat_log(session_id=request.session_id, sender="bot", category="cert_quiz", log=bot_msg)
        
        return result
    except Exception as e:
        logger.error(f"cert quiz check error: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@file_router.get("/cert-img/{section}/{filename}")
async def get_cert_img(section: str, filename: str):
    """cert_questions 관련 이미지 서빙 (question_img, solution_img)"""
    from fastapi.responses import FileResponse
    import os
    img_path = os.path.join(IMG_EXP_PATH, section, filename)
    if not os.path.exists(img_path):
        # img_q 폴더도 확인
        img_path = os.path.join(IMG_Q_PATH, section, filename)
    if not os.path.exists(img_path):
        raise HTTPException(status_code=404, detail="Image not found")
    return FileResponse(img_path)

@router.post("/fe/complete")
async def complete_fe_phase():
    try:
        client = get_gemini_model()
        prompt = """
        ユーザーが基本情報技術者試験（FE）の難しい問題をすべてクリアしました。
        親しい友人として、最高の称賛を送ってください。

        [制約事項 - 厳守]
        1. **超短文**: 長い文章は禁止。テンポよく短く。「マジですごい！」「天才かよ！」など。
        2. **分割**: メッセージを2〜3つの短い吹き出しに分けるため、間に「|||」を入れる。
        3. **強調**: 「**完走**」「**すごい**」「**デバッグ日誌**」などの重要単語は太字にする。
        4. **内容**: 
           - まず完走したことを手放しで褒める。
           - 最後に「今日の学びを忘れないように、**デバッグ日誌**を書こう！」と提案する。
        """
        response = client.models.generate_content(
            model="gemini-2.5-flash",
            contents=[types.Content(role="user", parts=[types.Part(text=prompt)])]
        )
        return {"message": response.text}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

# 2. 디버그 일지 인터뷰 채팅
# @router.post("/journal/chat")
# async def chat_journal(request: ChatCurriculumRequest):
#     try:
#         client = get_gemini_model()
        
#         # 1. 대화 내역 문자열 변환
#         history_context = ""
#         if request.history:
#             for entry in request.history:
#                 role = "User" if entry['role'] == "user" else "AI"
#                 history_context += f"{role}: {entry['text']}\n"

#         # 2. 시스템 프롬프트 (집요함 방지 룰 추가)
#         system_instruction = """
#         あなたはユーザーの学習を振り返る「デバッグ日誌」の作成を手伝うパートナーです。
#         以下の4つのフェーズ（Phase）に沿って、親しい友人のように質問をしてください。
        
#         [進行フェーズ]
#         Phase 1. 状況把握: 今日の勉強の感想や進捗を聞く。
#         Phase 2. デバッグ: エラー内容や詰まった箇所を聞く。
#         Phase 3. 解決策の参照: 参考にした資料（動画・PPT）を聞く。
#         Phase 4. 解決: 最終的な解決方法と、今の気持ちを聞く。

#         [重要: 会話のルール]
#         1. **深掘り禁止**: ユーザーが「忘れた」「ただ難しかった」「わからない」と曖昧な回答をした場合、**無理に聞き出そうとせず、すぐに「そっか、そういうこともあるよね！」と受け入れて次のフェーズに進んでください。**
#         2. **繰り返し禁止**: ユーザーが同じような回答を2回繰り返したら、これ以上情報は出ないと判断し、次のフェーズに進んでください。
#         3. **内部用語の隠蔽**: プロンプトにある「（壁）」や「Phase N」といった単語は絶対に出力しないでください。
#         4. **完遂優先**: 完璧な情報を集めることよりも、気持ちよく会話を終わらせることを優先してください。

#         [終了判定]
#         全てのフェーズが終わった、またはこれ以上聞くのが野暮だと判断したら:
#         JSONで {"is_finished": true, "message": "OK! いろいろ教えてくれてありがとう！バッチリ整理できそうだよ！"} を返してください。
        
#         まだ途中なら:
#         JSONで {"is_finished": false, "message": "次の質問..."} を返してください。
#         """
        
#         prompt = f"""
#         [これまでの会話履歴]
#         {history_context}
        
#         [ユーザーの最新の発言]
#         "{request.user_message}"
        
#         履歴を分析し、ユーザーが答えに窮している場合や、曖昧な回答の場合は、深掘りせずに次のフェーズの質問に移ってください。
#         """
        
#         response = client.models.generate_content(
#             model="gemini-2.5-flash",
#             contents=[types.Content(role="user", parts=[types.Part(text=prompt)])],
#             config={
#                 "system_instruction": system_instruction,
#                 "response_mime_type": "application/json"
#             }
#         )
#         return json.loads(response.text)
#     except Exception as e:
#         raise HTTPException(status_code=500, detail=str(e))

@router.post("/journal/interview/chat")
async def chat_journal(request: ChatCurriculumRequest):
    try:
        client = get_gemini_model()
        history = request.history or []
        user_input = request.user_message
        
        # 1. 일지 시작 (첫 질문)
        if user_input == "日誌作成を始めよう":
            start_prompt = """
            あなたはユーザーの親しい友人（Best Friend）です。
            今からユーザーと一緒に「学習日誌（デバッグ日誌）」を作成します。
            
            [タスク]
            最初の質問をしてください。
            「よし、日誌書こうか！今日の勉強、どんな感じだった？印象に残ってることとか、進捗はどうかな？」
            というニュアンスで、明るく聞いてください。
            """
            response = client.models.generate_content(
                model="gemini-2.5-flash",
                contents=[types.Content(role="user", parts=[types.Part(text=start_prompt)])]
            )
            # Goalskill 분류: Part C, AI 일지 시작 질문
            await classify_and_save(session_id=request.session_id, sender="I", part="C", text=response.text)
            save_chat_log(session_id=request.session_id, sender="bot", category="curriculum", log=response.text)
            return {"is_finished": False, "message": response.text}

        # 대화 턴 수에 따른 시나리오 진행 (0:시작, 1:AI질문1, 2:User답1, 3:AI질문2...)
        turn_count = len(history)

        # Step 1: 소감 듣고 -> 어려웠던 점 물어보기
        if turn_count <= 2:
            step_1_prompt = f"""
            ユーザーの回答: "{user_input}"
            あなたは親しい友人です。ユーザーが今日の感想を言いました。
            
            [タスク]
            1. まず共感してください（「そっか、楽しかったんだね！」「大変だったね」など）。
            2. 次に、「具体的にどこか詰まっちゃったところとか、エラーが出たところはあった？どんなことでも教えて！」と聞いてください。
            """
            response = client.models.generate_content(
                model="gemini-2.5-flash",
                contents=[types.Content(role="user", parts=[types.Part(text=step_1_prompt)])]
            )
            # Goalskill 분류: Part C, User 일지 답변 + AI 질문
            await classify_and_save(session_id=request.session_id, sender="M", part="C", text=user_input)
            save_chat_log(session_id=request.session_id, sender="user", category="curriculum", log=user_input)
            await classify_and_save(session_id=request.session_id, sender="I", part="C", text=response.text)
            save_chat_log(session_id=request.session_id, sender="bot", category="curriculum", log=response.text)
            return {"is_finished": False, "message": response.text}

        # Step 2: 어려웠던 점 듣고 -> 참고한 자료 물어보기 (★ 여기가 수정된 부분 ★)
        elif turn_count <= 4:
            step_2_prompt = f"""
            ユーザーの回答: "{user_input}"
            あなたは親しい友人です。ユーザーが「難しかった場所」や「エラー」について答えました。

            [制約事項 - **深掘り禁止(Do Not Dig Deeper)**]
            1. **即座に受容**: 回答が短くても、具体的でなくても、「そっか、そこが難しかったんだね」とすぐに受け入れてください。
            2. **質問禁止**: 「具体的にどんなエラー？」「どう解決した？」と**聞き返さないでください**。
            3. **次の話題へ**: すぐに「そういう時、何か参考にした動画とか資料とかはあったかな？」と次の質問に進んでください。
            """
            response = client.models.generate_content(
                model="gemini-2.5-flash",
                contents=[types.Content(role="user", parts=[types.Part(text=step_2_prompt)])]
            )
            # Goalskill 분류: Part C, User 일지 답변 + AI 질문
            await classify_and_save(session_id=request.session_id, sender="M", part="C", text=user_input)
            save_chat_log(session_id=request.session_id, sender="user", category="curriculum", log=user_input)
            await classify_and_save(session_id=request.session_id, sender="I", part="C", text=response.text)
            save_chat_log(session_id=request.session_id, sender="bot", category="curriculum", log=response.text)
            return {"is_finished": False, "message": response.text}

        # Step 3: 참고자료 듣고 -> 해결 여부/今の気持ち 물어보기
        elif turn_count <= 6:
            step_3_prompt = f"""
            ユーザーの回答: "{user_input}"
            あなたは親しい友人です。ユーザーが参考にした資料について答えました。
            
            [タスク]
            1. 「おお、それを見て頑張ったんだね！」と褒める。
            2. 最後に「その動画とかを見て、最終的に問題は解決できたかな？今はどんな気持ち？」と聞いて、締めくくりの準備をして。
            """
            response = client.models.generate_content(
                model="gemini-2.5-flash",
                contents=[types.Content(role="user", parts=[types.Part(text=step_3_prompt)])]
            )
            # Goalskill 분류: Part C, User 일지 답변 + AI 질문
            await classify_and_save(session_id=request.session_id, sender="M", part="C", text=user_input)
            save_chat_log(session_id=request.session_id, sender="user", category="curriculum", log=user_input)
            await classify_and_save(session_id=request.session_id, sender="I", part="C", text=response.text)
            save_chat_log(session_id=request.session_id, sender="bot", category="curriculum", log=response.text)
            return {"is_finished": False, "message": response.text}

        # Step 4: 마무리 및 저장
        else:
            final_prompt = f"""
            ユーザーの回答: "{user_input}"
            あなたは親しい友人です。これでインタビューは終了です。
            
            [タスク]
            1. 「よし！これで今日の日誌はバッチリだね！」と明るく締める。
            2. 「ゆっくり休んでね！」と労う。
            3. これ以上の質問はしない。
            """
            response = client.models.generate_content(
                model="gemini-2.5-flash",
                contents=[types.Content(role="user", parts=[types.Part(text=final_prompt)])]
            )
            # Goalskill 분류: Part C, User 일지 마지막 답변 + AI 마무리
            await classify_and_save(session_id=request.session_id, sender="M", part="C", text=user_input)
            save_chat_log(session_id=request.session_id, sender="user", category="curriculum", log=user_input)
            await classify_and_save(session_id=request.session_id, sender="I", part="C", text=response.text)
            save_chat_log(session_id=request.session_id, sender="bot", category="curriculum", log=response.text)
            return {"is_finished": True, "message": response.text}

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

class InterviewGenerateRequest(BaseModel):
    session_id: str
    target_day: int
    conversation_history: list

class AutoGenerateJournalRequest(BaseModel):
    session_id: str

# 3. 디버그 일지 생성 (자동 생성 - 인터뷰 전 필수 실행)
@router.post("/journal/auto-generate")
async def auto_generate_journal(request: AutoGenerateJournalRequest):
    try:
        client = get_gemini_model()
        
        # 오늘 날짜 확인
        progress = curriculum_module.get_user_progress(request.session_id)
        current_day = progress['current_day'] if progress else 1
        
        item_info = curriculum_module.get_today_item_info(request.session_id, current_day)
        item_name = item_info['name'] if item_info else "今日の学習内容"
        
        # 오늘치 채팅/퀴즈 상황 로그 가져오기
        from app.models.chat_log_module import get_chat_logs
        raw_chat_logs = get_chat_logs(request.session_id, category="curriculum", daily=current_day)
        chat_logs = "\n".join([f"{row['sender']}: {row['log']}" for row in raw_chat_logs[-30:]]) if raw_chat_logs else "ログなし"
        quiz_logs = get_daily_quiz_logs(request.session_id)
        
        prompt = f"""
        ユーザーは今日のカリキュラム（テーマ: {item_name}）の基本フェーズ（動画、PPT、確認テスト）を全て完了しました。
        これまでのチャット・クイズ回答ログは以下の通りです。
        
        [最近のチャットログ]
        {chat_logs}

        [今日のクイズ回答結果]
        {quiz_logs}
        
        [タスク]
        ログからユーザーの「理解できている点」と「弱点・つまづいた点」を抽出し、以下の要素を持つ「デバッグ日誌」を作成してください。
        無条件に称賛するだけでなく、チャットログの内容からユーザーが苦戦した部分（弱点）を指摘し、それをどう補強すれば良いか的確なアドバイスを含めてください。
        
        1. **summary_content**: 学習内容（{item_name}）とチャットログを元に、指定されたMarkdown形式で「デバッグ日誌」のベースを作成する。
           形式例:
           #### 📅 **今日の学習記録 | Topic: {item_name}**
           * **🔍 学習内容:** ...
           * **📓 完了したタスク:** ...
           * **⚠️ 発見された弱点 / 課題:** (ログから読み取れるユーザーの弱点や間違えたクイズの内容など)
           
        2. **understanding_score**: チャット上の理解度やクイズの正答状況を踏まえて、0〜100のスコアを設定する。
        3. **ai_feedback**: 発見された弱点をどのように補強すべきか、具体的な改善策やアドバイスを書く。(例: 〇〇の概念が混乱しているため、復習をお勧めします)
        4. **praise_content**: 課題に直面しつつも最後までやり遂げたことへの称賛を書く。
        
        出力は必ず以下のJSONフォーマットのみにしてください：
        {{
            "summary_content": "...",
            "understanding_score": 85,
            "ai_feedback": "...",
            "praise_content": "..."
        }}
        """
        
        response = client.models.generate_content(
            model="gemini-2.5-flash",
            contents=[types.Content(role="user", parts=[types.Part(text=prompt)])],
            config={"response_mime_type": "application/json"}
        )
        
        result = json.loads(response.text)
        
        # DB 저장 (target_date = current_day)
        saved = curriculum_module.save_debug_journal(
            request.session_id, 
            current_day, 
            result['summary_content'],
            result['understanding_score'],
            result['ai_feedback'],
            result['praise_content']
        )
        
        if not saved:
            raise Exception("DB Save Failed for Auto Journal")

        # ★ デバッグ日誌書込み完了 = 当該日付の user_curriculum.status に完了日を記録
        try:
            curriculum_module.mark_curriculum_completed(request.session_id, current_day)
        except Exception as mark_e:
            logger.error(f"Mark curriculum completed warning: {mark_e}")

        # ★ C파트 완료 = 1일차 전체 흐름 완료 → a_part_status를 1로 변경
        from app.models.general_module import update_a_part_status
        update_a_part_status(request.session_id, 1)
        
        from app.models.goalskill_module import create_result_row
        next_day = current_day + 1
        create_result_row(request.session_id, next_day)
        
        # カテゴリ別進捗率を再計算して保存
        try:
            curriculum_module.update_category_progress(request.session_id, current_day)
        except Exception as prog_e:
            logger.error(f"Category Progress Update Warning: {prog_e}")
        
        try:
            curriculum_module.update_progress_excel_and_pdf(request.session_id)
        except Exception as file_e:
            logger.error(f"File Update Warning: {file_e}")
            
        return {"status": "success", "target_day": current_day, "next_day": next_day}

    except Exception as e:
        logger.error(str(e))
        raise HTTPException(status_code=500, detail=str(e))

# 4. 인터뷰 통합 일지 업데이트
@router.post("/journal/interview/generate")
async def interview_journal_generate(request: InterviewGenerateRequest):
    try:
        client = get_gemini_model()
        
        # 1. 기존 자동일지 조회
        existing_journal = curriculum_module.get_debug_journal(request.session_id, request.target_day)
        if not existing_journal:
            raise Exception("Base auto journal not found for target day")
        
        # 2. 인터뷰 대화 내역 문자열
        conversation_text = "\n".join([f"{entry['role']}: {entry['text']}" for entry in request.conversation_history])
        
        # 3. 통합 프롬프트 
        prompt = f"""
        あなたは事前に作成された「デバッグ日誌」を、ユーザーとの「インタビュー内容」をもとに、より詳細で豊かな内容に統合・アップデートする役割です。
        
        [事前に作成されたデバッグ日誌]
        Summary: {existing_journal['summary_content']}
        Feedback: {existing_journal['ai_feedback']}
        Praise: {existing_journal['praise_content']}
        
        [インタビュー内容]
        {conversation_text}
        
        [タスク]
        インタビューで得られた新しい感情、具体的に詰まった点（デバッグ）、参考にした資料の所感、解決策などを既存の日誌に自然に統合してください。
        フォーマットは事前と同じMarkdown形式を維持しつつ、記述をよりパーソナライズされた具体的なものへ進化させること。
        
        出力は必ず以下のJSONフォーマットのみにしてください：
        {{
            "summary_content": "...",
            "understanding_score": 85,
            "ai_feedback": "...",
            "praise_content": "..."
        }}
        """
        
        response = client.models.generate_content(
            model="gemini-2.5-flash",
            contents=[types.Content(role="user", parts=[types.Part(text=prompt)])],
            config={"response_mime_type": "application/json"}
        )
        
        result = json.loads(response.text)
        
        # 4. DB 동일 행 업데이트 (ON DUPLICATE KEY UPDATE)
        saved = curriculum_module.save_debug_journal(
            request.session_id, 
            request.target_day, 
            result['summary_content'],
            result['understanding_score'],
            result['ai_feedback'],
            result['praise_content']
        )
        
        if not saved:
            raise Exception("DB Save Failed for Interview Journal Integration")
            
        # Goalskill 분류: Part C, AI 일지 생성 결과 (업데이트분)
        journal_text = f"{result['summary_content']} {result['ai_feedback']} {result['praise_content']}"
        await classify_and_save(session_id=request.session_id, sender="I", part="C", text=journal_text)
        save_chat_log(session_id=request.session_id, sender="bot", category="curriculum", log=journal_text)
            
        return {"status": "success", "day": request.target_day}

    except Exception as e:
        logger.error(str(e))
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/journal/view")
async def view_journal(request: GetJournalRequest):
    try:
        progress = curriculum_module.get_user_progress(request.session_id)
        current_day = progress['current_day'] if progress else 1
        
        # current_day는 일지 생성 후 이미 +1 된 상태이므로, 
        # 방금 작성한 일지는 current_day - 1 에 있음
        journal = curriculum_module.get_debug_journal(request.session_id, current_day)
        if not journal and current_day > 1:
            journal = curriculum_module.get_debug_journal(request.session_id, current_day - 1)
        
        if not journal:
            return {"found": False, "message": "日誌が見つかりません。"}
            
        return {"found": True, "data": journal}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
    
@router.get("/journal/history/{session_id}")
async def get_journal_history(session_id: str):
    try:
        history = curriculum_module.get_all_debug_journals(session_id)
        
        if not history:
            return {"count": 0, "data": []}
        
        # 날짜 포맷팅 (datetime -> "yyyy-MM-dd")
        data = []
        for row in history:
            date_str = row['created_at'].strftime('%Y-%m-%d') if row['created_at'] else "Unknown"
            data.append({
                "date": date_str,
                "summary_content": row['summary_content'],
                "ai_feedback": row['ai_feedback'],
                "praise_content": row['praise_content']
            })
            
        return {"count": len(data), "data": data}

    except Exception as e:
        logger.error(str(e))
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/progress/{session_id}")
async def get_progress(session_id: str):
    """ユーザーのカテゴリ別学習進捗率を取得"""
    try:
        data = curriculum_module.get_category_progress(session_id)
        return {"progress": data}
    except Exception as e:
        logger.error(f"Progress Error: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/plan/{session_id}")
async def get_plan(session_id: str):
    """ユーザーのカリキュラム計画（ガントチャート）を取得"""
    try:
        data = curriculum_module.get_curriculum_plan(session_id)
        return {"plan": data}
    except Exception as e:
        logger.error(f"Plan Error: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/category-detail/{session_id}")
async def get_category_detail(session_id: str, group: str = "CERT"):
    """カテゴリ別(自格証/PJT)の学習項目一覧と完了状態を取得"""
    try:
        group_norm = (group or "CERT").upper()
        if group_norm not in ("CERT", "PJT"):
            raise HTTPException(status_code=400, detail="group must be CERT or PJT")
        data = curriculum_module.get_category_detail(session_id, group_norm)
        return data
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Category Detail Error: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/item-resources/{session_id}/{item_id}")
async def get_item_resources(session_id: str, item_id: int):
    """完了済み項目の学習リソース取得。未完了項目は 403 を返す。"""
    try:
        data = curriculum_module.get_item_resources(session_id, item_id)
        if data is None:
            raise HTTPException(status_code=403, detail="この項目はまだ完了していません。")
        return data
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Item Resources Error: {e}")
        raise HTTPException(status_code=500, detail=str(e))
    

@file_router.get("/curriculum_pdf/{session_id}")
async def get_curriculum_pdf(session_id: str):
    """
    URL: /goal-skill-t/api/file/curriculum_pdf/{session_id}
    """
    # 파일이 위치한 디렉토리 경로
    base_dir = CURRICULUM_PDF_PATH
    file_name = f"curriculum_{session_id}.pdf"
    file_path = os.path.join(base_dir, file_name)
    
    # 파일 존재 여부 확인 후 전송
    if os.path.exists(file_path):
        return FileResponse(
            path=file_path,
            filename=file_name,
            media_type='application/pdf',
            content_disposition_type='inline'
        )
    else:
        raise HTTPException(status_code=404, detail="Curriculum PDF not found")
    

@file_router.get("/progress_pdf/{session_id}")
async def get_progress_pdf(session_id: str):
    """
    URL: /goal-skill-t/api/file/progress_pdf/{session_id}
    """
    # 진척도 PDF가 위치한 경로
    base_dir = PROGRESS_PDF_PATH
    file_name = f"progress_{session_id}.pdf"
    file_path = os.path.join(base_dir, file_name)
    
    # 파일 확인 및 전송 (inline으로 미리보기)
    if os.path.exists(file_path):
        return FileResponse(
            path=file_path,
            filename=file_name,
            media_type='application/pdf',
            content_disposition_type='inline' 
        )
    else:
        raise HTTPException(status_code=404, detail="Progress PDF not found")


# --------------------------------------------------------------------------
# AI カリキュラム生成
# --------------------------------------------------------------------------

class GenerateCurriculumRequest(BaseModel):
    session_id: str

@router.post("/generate")
async def generate_curriculum(request: GenerateCurriculumRequest):
    """
    master_items의 원본 순서 그대로 user_curriculum에 복사합니다.
    (★ AI 순서 재배치는 일시 비활성화 중 — generate_ai_curriculum 사용 시 주석 해제)
    """
    try:
        logger.info(f"[Generate] Curriculum request: {request.session_id}")

        # ★ master_items 순서 그대로 커리큘럼 생성
        _create_user_curriculum(request.session_id)

        # ★ 이전 generate_ai_curriculum 호출 (AI 순서 재배치)
        # result = await generate_ai_curriculum(request.session_id)
        # if not result["success"]:
        #     return {"status": "error", "message": result["message"], "item_count": 0}

        # ★ A파트 커리큘럼 생성 성공 시: 카테고리 진행률 초기화
        _init_category_progress(request.session_id)
        logger.info(f"[Generate] Post-curriculum init done: {request.session_id}")
        return {
            "status": "success",
            "message": "カリキュラムが作成されました",
            "item_count": -1  # 실제 항목 수는 여기서 반환하지 않음
        }
    except Exception as e:
        logger.error(f"[Generate] Error: {e}")
        return {
            "status": "error",
            "message": f"カリキュラム生成失敗: {str(e)}",
            "item_count": 0
        }
