from fastapi import APIRouter, HTTPException
from app.models import findgoal_module
from app.schemas.findgoal_schema import StartFindGoalRequest, AnswerFindGoalRequest
from app.core.config import get_gemini_model
from google.genai import types
from app.services.goalskill_classifier import classify_and_save
import json
import re

router = APIRouter(
    prefix="",
    tags=["FindGoal"]
)

SYSTEM_PROMPT_FINDGOAL = """
あなたはユーザーの学習動機を共に探し、導く「人間らしいAI学習パートナー」です。
ユーザーが学習を続けるための「具体的な目標」を簡潔に把握してください。

【厳守：人間らしい自然な会話（Human AI）】
❌ 以下の「ロボットのような話し方」は絶対に禁止です：
- 「〜とのことですね。了解しました！」のように、ユーザーの言葉を単純に繰り返す（オウム返し）。
- 「〜聞かせてもらえませんか？」「〜どうかな？」と毎回同じ語尾で質問を終える。
- ユーザーにとって答えるのが難しい質問（「どんな工学的な考え方が活かせそうか？」など）を執拗に掘り下げる。

⭕ 以下の「プロのパートナーとしての話し方」をしてください：
- ★ ユーザーの言葉に対して、まずは感情を込めて「1行以上の共感・リアクション」をすること。（例：「いいですね！初めての資格ってワクワクしますよね！」「そういうことだったんですね、よく分かります😊」）
- ユーザーの答えた内容を受け止める「ブリッジ（繋ぎの言葉）」を入れてから次の提案をする。いきなり論理的な解決策（「じゃあ〇〇しましょう」）に飛ばないこと。
  まずは「じゃあ、まだ探してる途中って感じですかね」「無理に決めなくても全然大丈夫ですよ😊 軽く触るだけでもいいので」と**一度目的を急ぐのをやめて（譲歩して）**安心させてください。
  ★【重要】その上で提案を続ける場合は、ユーザーが読みやすいように文を区切り、「ちなみに、他の人はこういう理由で始めることが多いんですが…」のように余談のように軽く提案してください。（※JSON内で物理的な改行をするとエラーになるため、改行したい場合は必ず `\\n` と文字で出力してください）

【最重要ルール：早く確定すること】
★★★ 質問は最大2回まで。3回目以降は絶対に質問せず、目標を確定してください。
★★★ 具体的なキーワード（Python、資格名、就職、転職、プログラミング等）が出たら、
      それ以上深掘りせず、すぐに最終確認に移行してください。

【目標の誘導と提案 — カリキュラム構造を反映】
- ユーザーの目標が漠然としている、または「わからない」と答えた場合、以下の方向へ**余談のように自然に**提案してください：
  1. **Pythonプログラミング学習**（初日からPythonの授業が始まります）
  2. **基本情報技術者試験の取得**（3日目から資格対策の授業が始まります）
  3. **就職・転職**（IT業界への就職・転職を目指す）
- ユーザーがプログラミング・コーディングに興味がある場合 → **Python学習**を中心に提案
- ユーザーが資格取得に興味がある場合 → **基本情報技術者試験**を中心に提案
- ユーザーが漠然としている場合 → **Python + 基本情報の両方**を含めた提案をする
  （例：「ここではPythonプログラミングから始めて、基本情報技術者試験の対策もできるんですが、ちょっとだけでも興味あったりしますか？」）
- 提案したら、ユーザーの同意をとるための確認（confidence: 0.8）に進んでください。

【終了条件と最終確認】
1. **即座確認が必要な場合 (confidence: 0.8)**: 
   - ユーザーが具体的な目標を出した、またはAIの提案を提示するタイミング。
   - 深掘り質問はしない。理由を聞かない。すぐに確認する。
   
2. **確定ステップ (confidence: 0.95)**:
   - AIの確認に対して、ユーザーが「はい」「ウン」「いいよ」「やってみる」「そうかもしれない」などと**肯定的な反応**を示した場合。
   - ここで初めて confidence: 0.95 を出して目標を完了させる。

3. **【非常に重要】ユーザーが提案を「拒否」した場合（「いやだ」「違う」など）**:
   - ユーザーが提案を拒否したのに「あなたの目標は〇〇ですね！」と無理やり確定するのは**絶対にやめてください**。
   - 拒否された場合は、「なるほど、分かりました！😊 無理に今すぐ決める必要は全くありませんよ。まずは色々な学習を経験しながら、ゆっくり自分に合うものを見つけていきましょうね！」と優しく受け入れ、`confidence: 0.95` とし、`final_goal` を「まずは自分に合う学習スタイルや目標をゆっくり見つけること」として完了させてください。

【最重要ルール：早く確定すること】
★★★ 質問のやり取りが長引くのは避けてください。3回目以降のやり取りになった場合、それ以上の深掘りはせず、肯定ならその目標で確定、迷いや拒否があれば上記の「拒否された場合」の対応を用いて、必ず目標探しを完了（confidence: 0.95）させてください。

【出力フォーマット (JSON)】
{
    "confidence": 0.5,
    "reasoning": "ユーザーはITに興味があるが具体例がわからない状態。共感してから、PythonとFEの両方を提案してリードする。",
    "next_question": "ITは広くて最初は迷いますよね、分かりますよ！😊 大丈夫です。ここではまずPythonプログラミングの基礎から始めて、3日目からは基本情報技術者試験の対策も本格的にやっていきます。まずは一緒にPythonから始めてみませんか？",
    "final_goal": "（confidenceが0.9以上の場合のみ）Pythonプログラミング学習と基本情報技術者試験の取得"
}

【例 — 迷っているユーザーをリードするパターン】
ユーザー：「これから何をすればいいの？」「特にない」
→ confidence: 0.8, next_question: "じゃあ、まだ探してる途中って感じですかね😊 無理に決めなくても全然大丈夫ですよ！最初は軽く触ってみるだけでもいいんです。\n\nちなみに参考までに、ここではPythonプログラミングの基礎から学べて、後々IT系の資格対策もできるんですが、少し興味あったりしますか？"

【例 — プログラミングに興味がある・資格に興味がある】
ユーザー：「資格を一度取得してみたいですね。」
→ [悪い例]：「基本情報技術者試験はいかがでしょうか？」 (共感ブリッジがなく唐突すぎる)
→ [良い例]：confidence: 0.8, next_question: "いいですね！初めての資格ってちょっとワクワクしますよね✨ IT系への就職に有利な『基本情報技術者試験』などは興味ありませんか？"
"""


@router.post("/start")
async def start_findgoal(request: StartFindGoalRequest):
    try:
        client = get_gemini_model()
        base_question = """まず、ここで何を達成したいかお伺いしてもいいですか？
(例：資格を取得したい、会社で昇進したい など)"""

        rephrase_prompt = f"""
あなたは親しみやすいコーチです。
以下の「基準質問」を、緊張せずに答えられるように「自然で温かい日本語」に変更してください。
[基準質問] :
"{base_question}"
【遵守事項】
1. **意味は絶対に変えない**：GOALSKILLで達成したい目標を尋ねること
2. **重要**: 挨拶は含めないでください（既に一般チャットで挨拶済みのため）
3. **重要**: 「せっかく来てくださったので、どんなことに興味あるのかなって少し気になりました😊」といった感じで、**面接のような質問やフォーム入力のように聞こえない、人間らしくて自然な言い回し**に変更してください。
4. **重要**: 応答は必ず2つのメッセージに分けてください：
   - 1つ目: **自然な質問のみ**（例：「まずは、ここでどんなことをしてみたいな～とか、なんとなくの目標ってありますか？😊」）
   - 2つ目:**例のみ提示** Pythonを学ぶ旨と資格を取得する旨は必ず含めてください。（例：「例えば、IT分野の資格を取りたい、Pythonを学びたい、自由に教えていただいて構いません！」）
4. **絶対に守ること**: 
   - 1つ目のメッセージには質問だけを含め、例は含めないでください
   - 2つ目のメッセージには例だけを含め、質問は含めないでください
5. **例は必ず2つ目のメッセージに含める必要があります**：資格取得、昇進などの例を必ず含めてください
出力は2つのメッセージを改行で区切って返してください（1つ目のメッセージ、改行、2つ目のメッセージ）。
"""
        
        # 4. AI 호출
        response = client.models.generate_content(
            model="gemini-2.5-flash",
            contents=[types.Content(role="user", parts=[types.Part(text=rephrase_prompt)])]
        )
        
        ai_response = response.text.strip()
        
        # 5. AI가 빈 응답 주면 기준 질문 사용 (안전장치)
        if not ai_response:
            ai_response = base_question
        
        # 6. 응답을 2개로 나누기 (改行で区切られている場合)
        questions = [q.strip() for q in ai_response.split('\n') if q.strip()]
        
        if len(questions) >= 2:
            # 2개 이상이면 첫 번째와 두 번째를 분리
            first_question = questions[0]
            second_question = questions[1]
            # DB에는 전체를 하나로 저장 (대화 흐름 유지)
            full_question = f"{first_question}\n{second_question}"
        else:
            # 1개만 있으면 그대로 사용
            first_question = questions[0] if questions else ai_response
            second_question = None
            full_question = first_question
        
        # 7. DB에 저장 (user_id 제거)
        findgoal_module.save_question(
            session_id=request.session_id,
            step_order=1,
            question_text=full_question
        )
        
        await classify_and_save(
            session_id = request.session_id,
            sender = "I",
            part = "A",
            text = full_question
        )
        # 8. 프론트에 반환 (2개로 나뉘어 있으면 배열로 반환)
        if second_question:
            return {
                "questions": [first_question, second_question],
                "step": 1
            }
        else:
            return {
                "question": first_question,
                "step": 1
            }

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
        


async def analyze_with_gemini(session_id: str, user_answer: str):

    try:
        # 1. AIクライアントの取得
        client = get_gemini_model()

        # 2. DBから全体の会話履歴を取得
        history_list = findgoal_module.get_conversation_history(session_id)

        # 3. 会話履歴をテキストに変換
        history_text = ""
        for h in history_list:
            if h['question_text']:
                history_text += f"AI: {h['question_text']}\n"
            if h['answer_text']:
                history_text += f"User: {h['answer_text']}\n"

        # 4. AI에게 보낼 프롬프트 구성
        user_prompt = f"""
        [今までの会話履歴]:
        {history_text}
        [Userの最新の回答]:
        {user_answer}
        上記の流れを踏まえて、次のレスポンスをJSON形式で生成してください。
"""

        # 5. AI 호출 (SYSTEM_PROMPT 적용)
        response = client.models.generate_content(
            model="gemini-2.5-flash",
            contents=[types.Content(role="user", parts=[types.Part(text=user_prompt)])],
            config={
                "system_instruction": SYSTEM_PROMPT_FINDGOAL,
                "response_mime_type": "application/json"
            }
        )

        # 6. JSON 파싱해서 반환
        try:
            result = json.loads(response.text, strict=False)
        except json.JSONDecodeError:
            # Markdown block 등 불필요한 문자열 제거 시도
            raw_text = response.text.strip()
            raw_text = re.sub(r'^```json\s*', '', raw_text)
            raw_text = re.sub(r'^```\s*', '', raw_text)
            raw_text = re.sub(r'```$', '', raw_text).strip()
            
            try:
                result = json.loads(raw_text, strict=False)
            except json.JSONDecodeError as je:
                print(f"Gemini JSON Parse Error (Recover Failed): {je}\nRaw Text: {raw_text}")
                return {
                    "confidence": 0.5,
                    "next_question": "なるほど、まだ具体的な目標はないんですね！大丈夫ですよ😊焦らず、まずは何か一つ小さなことから一緒に探してみましょうか？",
                    "reasoning": "JSON Parse Error - AI応答をパースできませんでした"
                }

        # 안전장치: next_question이 비어있거나 없는 경우 기본값
        if not result.get("next_question") and result.get("confidence", 0) < 0.9:
            result["next_question"] = "うまく聞き取れませんでした💦 何か興味のある分野や、やってみたいことはありますか？😊"
        
        return result

    except Exception as e:
        # AI 에러 시 기본 응답 반환 (시스템이 멈추지 않게)
        print(f"Gemini Error: {e}")
        return {
            "confidence": 0.0,
            "next_question": "すみません、通信に少し問題が起きたみたいです💦 もう一度教えていただけますか？😊",
            "reasoning": f"AI Error: {str(e)}"
        }

@router.post("/answer")
async def answer_findgoal(request: AnswerFindGoalRequest):
    """
    사용자 답변 처리 API
    
    왜 필요한가?
    - 사용자가 답변을 입력할 때마다 호출
    - 답변을 DB에 저장하고 AI로 분석
    - confidence가 0.9 이상이면 목표 확정, 아니면 다음 질문 생성
    """
    try:
        # ============================================
        # 1. 이전 질문 정보 가져오기
        # ============================================
        # - 현재 몇 번째 대화인지 파악 (step_order)
        # - 답변을 어느 질문에 연결할지 알아야 함 (question_id)
        # - DB의 Q-A 관계를 연결하기 위해 필수
        
        last_question = findgoal_module.get_last_question(request.session_id)
        
        if not last_question:
            # 질문이 없다 = /start를 안 호출했다
            raise HTTPException(status_code=400, detail="No question found. Call /start first.")
        
        current_step = last_question['step_order']
        question_id = last_question['id']
        
        
        # ============================================
        # 2. 사용자 답변 DB에 저장 (findgoal_A)
        # ============================================
        # - 대화 내역을 모두 기록해야 나중에 AI가 전체 흐름을 이해할 수 있음
        # - 사용자가 뭐라고 답했는지 추적 가능 (디버깅, 분석에 필수)
        
        answer_id = findgoal_module.save_answer(
            session_id=request.session_id,
            question_id=question_id,
            answer_text=request.user_answer
        )
        
        await classify_and_save(
            session_id = request.session_id,
            sender = "M",
            part = "A",
            text = request.user_answer
        )
        
        # ============================================
        # 3. AI로 답변 분석
        # ============================================
        # - 사용자 답변만으로는 "목표를 찾았는지" 판단 불가
        # - AI가 전체 대화 흐름을 보고 confidence 점수 계산
        # - 다음에 무엇을 물어볼지 AI가 결정
        
        ai_result = await analyze_with_gemini(
            session_id=request.session_id,
            user_answer=request.user_answer
        )
        
        try:
            confidence = float(ai_result.get('confidence', 0.0))
        except (ValueError, TypeError):
            confidence = 0.5
            
        reasoning = ai_result.get('reasoning', '')
        next_question_text = ai_result.get('next_question', '')
        final_goal = ai_result.get('final_goal', '')
        
        
        # ============================================
        # 4. AI 분석 결과 DB에 저장 (findgoal_P)
        # ============================================
        # - AI가 왜 이런 판단을 했는지 기록 (reasoning)
        # - confidence 변화 추적 (0.3 → 0.5 → 0.7 → 0.95 이런 흐름 분석 가능)
        # - 나중에 "AI가 어떤 근거로 목표를 찾았는지" 확인 가능
        
        findgoal_module.save_processing(
            session_id=request.session_id,
            confidence_score=confidence,
            reasoning=reasoning
        )
        
        
        # ============================================
        # 5. Confidence 확인 및 분기 처리
        # ============================================
        # 왜 필요한가?
        # - confidence < 0.9: 아직 목표가 명확하지 않음 → 대화 계속
        # - confidence ≥ 0.9: 목표를 찾았다! → 대화 종료, 최종 결과 저장
        
        # [강제 종료 안전장치] 대화가 5번(step_order 5) 이상 길어지면 강제로 무조건 종료시킴!
        if current_step >= 5 and confidence < 0.9:
            print(f"[FindGoal] Forced completion due to step limit (current_step: {current_step})")
            confidence = 0.95
            final_goal = final_goal if final_goal else "まずは自分に合う学習ペースと目標をゆっくり見つけること"
            next_question_text = "わかりました！😊 色々教えてくださってありがとうございます。まずは無理に急がず、少しずつ進めながら一緒に目標を見つけていきましょうね！"
            reasoning = "Forced completion - Max conversation turns reached"

        if confidence >= 0.9:
            # ============================================
            # 5-1. 목표 확정: findgoal_Output에 저장
            # ============================================
            # - C파트(커리큘럼 생성)에서 이 목표를 읽어서 사용
            # - 세션당 1개의 최종 목표만 저장 (ON DUPLICATE KEY UPDATE)
            
            findgoal_module.save_or_update_output(
                session_id=request.session_id,
                final_goal=final_goal
            )
            
            # user_profile_summary에도 동기화
            findgoal_module.sync_to_user_profile_summary(
                session_id=request.session_id,
                final_goal=final_goal
            )
            
            # 프론트에 "완료" 신호 전달
            return {
                "status": "completed",
                "confidence": confidence,
                "final_goal": final_goal,
                "reasoning": reasoning,
                "message": next_question_text if next_question_text else "目標が確定しました！"
            }
        
        else:
            # ============================================
            # 5-2. 대화 계속: 다음 질문 생성
            # ============================================
            # - AI가 아직 목표가 명확하지 않다고 판단 (confidence < 0.9)
            # - 더 깊이 파고들기 위해 다음 질문 필요
            
            next_step = current_step + 1
            
            # 다음 질문을 DB에 저장
            findgoal_module.save_question(
                session_id=request.session_id,
                step_order=next_step,
                question_text=next_question_text
            )
            
            await classify_and_save(
                session_id = request.session_id,
                sender = "I",
                part = "A",
                text = next_question_text
            )
            # final_goal이 있을 때만 user_profile_summary에 동기화
            if final_goal:
                findgoal_module.sync_to_user_profile_summary(
                    session_id=request.session_id,
                    final_goal=final_goal
                )
            # 프론트에 "다음 질문" 전달
            return {
                "status": "continue",
                "confidence": confidence,
                "question": next_question_text,
                "step": next_step,
                "reasoning": reasoning
            }
    
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/history/{session_id}")
async def get_findgoal_history(session_id:str):
    history  = findgoal_module.get_conversation_history(session_id)
    output = findgoal_module.get_output(session_id)

    return{
        "history": history,
        "final_goal": output,
        "has_history" : len(history) > 0
    }

@router.delete("/reset/{session_id}")
async def reset_findgoal(session_id: str):
    """FindGoal 대화 초기화 (재시작용)"""
    findgoal_module.reset_session(session_id)
    return {"status": "reset"}
