# ============================================================
# [실습] 6단계: 최종 통합본  (= 05 까지의 모든 기능을 다듬어 하나로)
#
# 새 개념은 없다. 01~05 를 합치고 다듬는다:
#   PDF/TXT 업로드·파싱 · 출처 · 목록/삭제 · 멀티턴 메모리 + 확장자 검증 + 2-패널 화면(06.html)
#
# 실행:  python 06_final_실습.py   →   http://localhost:5000
#
# 구현 항목:
#  1) get_session_history + conversational (05 와 동일)
#  2) /upload : 확장자(pdf/txt) 검증 후 파싱·청킹·인덱싱, DOC_IDS 누적
#  3) /ask    : 검색 → context → conversational.invoke → 답 + 출처
# ============================================================

import os
import uuid
from flask import Flask, request, jsonify, session, send_from_directory
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.output_parsers import StrOutputParser
from langchain_core.vectorstores import InMemoryVectorStore
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.document_loaders import PyPDFLoader, TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from dotenv import load_dotenv

load_dotenv()
app = Flask(__name__)
app.secret_key = "day3_final"
UPLOAD_DIR = "uploads"
os.makedirs(UPLOAD_DIR, exist_ok=True)
ALLOWED = {"pdf", "txt"}

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
prompt = ChatPromptTemplate.from_messages([
    ("system", "아래 [문서]와 이전 대화를 근거로 한국어로 간결히 답하세요. 문서에 없으면 '문서에 없습니다'라고만 답하세요."),
    MessagesPlaceholder("history"),
    ("human", "[문서]\n{context}\n\n[질문] {question}"),
])
chain = prompt | llm | StrOutputParser()

SESSIONS = {}


def get_session_history(session_id: str) -> InMemoryChatMessageHistory:
    # 1) 여기에 코드를 작성하세요
    pass


# 1) 여기에 코드를 작성하세요 (conversational = RunnableWithMessageHistory(...))

store = InMemoryVectorStore(OpenAIEmbeddings(model="text-embedding-3-small"))
DOC_IDS = {}


@app.get("/")
def index():
    return send_from_directory(app.static_folder, "06.html")


@app.post("/upload")
def upload():
    file = request.files.get("file")
    if not file or not file.filename:
        return jsonify({"error": "파일이 없습니다"}), 400
    # 2) 여기에 코드를 작성하세요
    #    확장자(ALLOWED) 검증 → 저장 → 로더(pdf/txt) → 청킹(800/100) → add → DOC_IDS 누적
    return jsonify({"message": f"'{file.filename}' 업로드 완료", "files": list(DOC_IDS)})


@app.delete("/files/<name>")
def delete_file(name):
    ids = DOC_IDS.pop(name, None)
    if not ids:
        return jsonify({"error": f"'{name}' 은(는) 없는 문서입니다"}), 404
    store.delete(ids=ids)
    return jsonify({"message": f"'{name}' 삭제됨", "files": list(DOC_IDS)})


@app.post("/ask")
def ask():
    if "sid" not in session:
        session["sid"] = uuid.uuid4().hex
    question = request.json["question"]
    hits = store.similarity_search(question, k=3)
    if not hits:
        return jsonify({"answer": "업로드된 문서가 없습니다.", "sources": []})
    # 3) 여기에 코드를 작성하세요
    #    context → conversational.invoke(..., config={"configurable": {"session_id": session["sid"]}}) → 답 + 출처
    pass


if __name__ == "__main__":
    app.run(debug=True, port=5000)
