"""
B-2: 자연어 SR 접수 챗봇 API 라우터

엔드포인트:
  POST /api/chatbot/message              — 메시지 전송 (대화 처리)
  GET  /api/chatbot/sessions             — 세션 목록
  GET  /api/chatbot/sessions/{key}       — 세션 상세 (대화 기록 포함)
  DELETE /api/chatbot/sessions/{key}     — 세션 종료
  GET  /api/chatbot/history/{key}        — 대화 기록만
  POST /api/chatbot/sessions/{key}/reset — 세션 초기화
"""
from __future__ import annotations

import json
import logging
from datetime import datetime
from typing import List, Optional

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import desc, select, and_
from sqlalchemy.ext.asyncio import AsyncSession

from database import get_db
from models import (
    ChatSession, ChatSessionOut,
    ChatMessage, ChatMessageOut,
    ChatMessageRequest, ChatResponse,
    SRRequest, SRStatus, SRType, Priority,
    AuditLog, compute_log_hash,
)
from core.chatbot import process_message, new_session_key

logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/chatbot", tags=["chatbot"])


# ── 헬퍼 ─────────────────────────────────────────────────────────────────────

async def _get_or_create_session(
    session_key: Optional[str],
    username: Optional[str],
    db: AsyncSession,
) -> ChatSession:
    """세션 키로 세션 조회 또는 신규 생성."""
    if session_key:
        sess = (await db.execute(
            select(ChatSession).where(ChatSession.session_key == session_key)
        )).scalars().first()
        if sess:
            return sess

    # 새 세션 생성
    key = session_key or new_session_key()
    sess = ChatSession(
        session_key  = key,
        username     = username or "anonymous",
        status       = "ACTIVE",
        context_json = json.dumps({"history": [], "collected": {}, "state": "GATHERING"}, ensure_ascii=False),
    )
    db.add(sess)
    await db.flush()
    return sess


def _parse_context(sess: ChatSession) -> dict:
    """세션 컨텍스트 파싱."""
    try:
        if sess.context_json:
            return json.loads(sess.context_json)
    except Exception:
        pass
    return {"history": [], "collected": {}, "state": "GATHERING", "intent": ""}


def _save_context(sess: ChatSession, context: dict) -> None:
    """세션 컨텍스트 저장."""
    sess.context_json = json.dumps(context, ensure_ascii=False)
    sess.updated_at   = datetime.utcnow()


# ── SR 자동 생성 ──────────────────────────────────────────────────────────────

async def _auto_create_sr(
    sr_data: dict,
    session_key: str,
    username: str,
    db: AsyncSession,
) -> Optional[SRRequest]:
    """챗봇에서 수집한 정보로 SR 자동 생성."""
    from core.srid import next_sr_id

    sr_id_val = await next_sr_id(db)

    priority_map = {
        "CRITICAL": Priority.CRITICAL,
        "HIGH":     Priority.HIGH,
        "MEDIUM":   Priority.MEDIUM,
        "LOW":      Priority.LOW,
    }
    type_map = {
        "DEPLOY":  SRType.DEPLOY,
        "RESTART": SRType.RESTART,
        "LOG":     SRType.LOG,
        "OTHER":   SRType.OTHER,
    }

    sr = SRRequest(
        sr_id        = sr_id_val,
        raw_text     = f"[챗봇] {sr_data.get('description', '')}",
        title        = sr_data.get("title", "챗봇 접수 SR"),
        description  = sr_data.get("description", ""),
        priority     = priority_map.get(sr_data.get("priority", "MEDIUM"), Priority.MEDIUM),
        sr_type      = type_map.get(sr_data.get("sr_type", "OTHER"), SRType.OTHER),
        status       = SRStatus.RECEIVED,
        requested_by = username or "chatbot",
        source       = "chatbot",
        created_at   = datetime.utcnow(),
    )
    db.add(sr)
    await db.flush()

    # 감사 로그
    last_log = (await db.execute(
        select(AuditLog).order_by(desc(AuditLog.id)).limit(1)
    )).scalars().first()
    prev_hash = last_log.log_hash if last_log else None
    ts = datetime.utcnow().isoformat()
    log_hash = compute_log_hash(prev_hash, username or "chatbot", "SR_CREATE_CHATBOT",
                                f"SR {sr_id_val} 챗봇 자동 생성", ts)
    db.add(AuditLog(
        sr_id    = sr_id_val,
        actor    = username or "chatbot",
        action   = "SR_CREATE_CHATBOT",
        detail   = f"챗봇 세션 {session_key}에서 SR 자동 접수",
        log_hash = log_hash,
    ))

    await db.commit()
    await db.refresh(sr)
    return sr


# ── 메시지 처리 ───────────────────────────────────────────────────────────────

@router.post("/message", response_model=ChatResponse)
async def send_message(
    body: ChatMessageRequest,
    use_llm: bool = Query(True, description="Ollama LLM 사용 여부 (False=규칙 기반)"),
    db: AsyncSession = Depends(get_db),
):
    """
    챗봇 메시지 전송 및 처리.
    - 신규 대화 시 session_key 미전송 → 새 세션 자동 생성
    - 기존 대화 계속 시 session_key 전송
    """
    if not body.message.strip():
        raise HTTPException(400, "메시지가 비어 있습니다.")

    # 세션 조회/생성
    sess = await _get_or_create_session(
        body.session_key, body.username, db
    )
    context = _parse_context(sess)

    # 사용자 메시지 저장
    user_msg = ChatMessage(
        session_id = sess.id,
        role       = "user",
        content    = body.message,
    )
    db.add(user_msg)
    await db.flush()

    # 대화 처리
    try:
        proc_result = await process_message(
            message         = body.message,
            session_context = context,
            use_llm         = use_llm,
        )
    except Exception as e:
        logger.error("[B-2] 메시지 처리 오류: %s", e)
        proc_result = {
            "intent":               "UNKNOWN",
            "entities":             {},
            "reply":                "죄송합니다. 처리 중 오류가 발생했습니다. 다시 시도해 주세요.",
            "needs_clarification":  False,
            "clarification_prompt": None,
            "action":               "NONE",
            "sr_data":              None,
            "confidence":           0.0,
        }

    intent   = proc_result["intent"]
    entities = proc_result["entities"]
    reply    = proc_result["reply"]
    action   = proc_result.get("action", "NONE")
    sr_data  = proc_result.get("sr_data")

    # SR 자동 생성
    created_sr = None
    if action == "CREATE_SR" and sr_data:
        try:
            created_sr = await _auto_create_sr(
                sr_data     = sr_data,
                session_key = sess.session_key,
                username    = body.username or sess.username or "chatbot",
                db          = db,
            )
            sess.created_sr_id = created_sr.sr_id
            sess.status        = "RESOLVED"

            type_ko = {
                "CRITICAL": "긴급",
                "HIGH": "높음",
                "MEDIUM": "보통",
                "LOW": "낮음",
            }.get(sr_data.get("priority", "MEDIUM"), "보통")

            reply = (
                f"✅ SR이 접수되었습니다!\n\n"
                f"- **SR ID**: {created_sr.sr_id}\n"
                f"- **제목**: {created_sr.title}\n"
                f"- **우선순위**: {type_ko}\n\n"
                f"담당자가 곧 연락드릴 예정입니다. 감사합니다."
            )
        except Exception as e:
            logger.error("[B-2] SR 자동 생성 오류: %s", e)
            reply = f"죄송합니다. SR 생성 중 오류가 발생했습니다: {str(e)[:50]}"

    # 어시스턴트 메시지 저장
    bot_msg = ChatMessage(
        session_id    = sess.id,
        role          = "assistant",
        content       = reply,
        intent        = intent,
        entities_json = json.dumps(entities, ensure_ascii=False),
        confidence    = proc_result.get("confidence", 0.5),
    )
    db.add(bot_msg)

    # 컨텍스트 업데이트
    context["history"].append({"role": "user", "content": body.message})
    context["history"].append({"role": "assistant", "content": reply})
    # 히스토리 최근 20개만 유지
    context["history"] = context["history"][-20:]
    context["collected"] = entities
    context["intent"]    = intent

    # 상태 전이
    if action == "CREATE_SR":
        context["state"] = "DONE"
    elif proc_result.get("needs_clarification"):
        context["state"] = "CONFIRMING" if context.get("state") == "GATHERING" else context.get("state", "GATHERING")
    else:
        context["state"] = "GATHERING"

    _save_context(sess, context)
    await db.commit()

    return ChatResponse(
        session_key          = sess.session_key,
        reply                = reply,
        intent               = intent,
        entities             = entities,
        action_taken         = action == "CREATE_SR",
        created_sr_id        = created_sr.sr_id if created_sr else None,
        needs_clarification  = proc_result.get("needs_clarification", False),
        clarification_prompt = proc_result.get("clarification_prompt"),
        suggestions          = _get_suggestions(intent),
    )


def _get_suggestions(intent: str) -> List[str]:
    """상황별 추천 발화."""
    if intent in ("SR_CREATE", "INCIDENT_REPORT"):
        return [
            "다른 서버도 문제가 있나요?",
            "현재 사용자에게 영향이 있나요?",
            "SR 목록 보여줘",
        ]
    return [
        "서버 장애 신고",
        "배포 요청",
        "SR-0001 상태 확인",
    ]


# ── 세션 관리 ─────────────────────────────────────────────────────────────────

@router.get("/sessions", response_model=List[ChatSessionOut])
async def list_sessions(
    status: Optional[str] = Query(None),
    username: Optional[str] = Query(None),
    limit: int = Query(20, ge=1, le=100),
    db: AsyncSession = Depends(get_db),
):
    """챗봇 세션 목록 조회."""
    q = select(ChatSession).order_by(desc(ChatSession.created_at)).limit(limit)
    if status:
        q = q.where(ChatSession.status == status.upper())
    if username:
        q = q.where(ChatSession.username == username)
    rows = (await db.execute(q)).scalars().all()
    return rows


@router.get("/sessions/{session_key}", response_model=ChatSessionOut)
async def get_session(
    session_key: str,
    db: AsyncSession = Depends(get_db),
):
    """세션 상세 (대화 기록 포함)."""
    from sqlalchemy.orm import selectinload
    q = (
        select(ChatSession)
        .options(selectinload(ChatSession.messages))
        .where(ChatSession.session_key == session_key)
    )
    sess = (await db.execute(q)).scalars().first()
    if not sess:
        raise HTTPException(404, f"세션 '{session_key}'를 찾을 수 없습니다.")
    return sess


@router.delete("/sessions/{session_key}", status_code=204)
async def end_session(
    session_key: str,
    db: AsyncSession = Depends(get_db),
):
    """세션 종료."""
    sess = (await db.execute(
        select(ChatSession).where(ChatSession.session_key == session_key)
    )).scalars().first()
    if not sess:
        raise HTTPException(404, f"세션 '{session_key}'를 찾을 수 없습니다.")
    sess.status = "ABANDONED"
    await db.commit()


@router.post("/sessions/{session_key}/reset", status_code=200)
async def reset_session(
    session_key: str,
    db: AsyncSession = Depends(get_db),
):
    """세션 초기화 (대화 기록 유지, 컨텍스트 리셋)."""
    sess = (await db.execute(
        select(ChatSession).where(ChatSession.session_key == session_key)
    )).scalars().first()
    if not sess:
        raise HTTPException(404, f"세션 '{session_key}'를 찾을 수 없습니다.")

    sess.context_json = json.dumps(
        {"history": [], "collected": {}, "state": "GATHERING"}, ensure_ascii=False
    )
    sess.status        = "ACTIVE"
    sess.created_sr_id = None
    sess.updated_at    = datetime.utcnow()
    await db.commit()
    return {"session_key": session_key, "status": "reset"}


@router.get("/history/{session_key}", response_model=List[ChatMessageOut])
async def get_history(
    session_key: str,
    limit: int = Query(50, ge=1, le=200),
    db: AsyncSession = Depends(get_db),
):
    """대화 기록 조회."""
    sess = (await db.execute(
        select(ChatSession).where(ChatSession.session_key == session_key)
    )).scalars().first()
    if not sess:
        raise HTTPException(404, f"세션 '{session_key}'를 찾을 수 없습니다.")

    msgs = (await db.execute(
        select(ChatMessage)
        .where(ChatMessage.session_id == sess.id)
        .order_by(ChatMessage.created_at)
        .limit(limit)
    )).scalars().all()
    return msgs


@router.get("/stats")
async def get_chatbot_stats(
    db: AsyncSession = Depends(get_db),
):
    """챗봇 사용 통계."""
    from sqlalchemy import func as sqlfunc
    total_sessions = (await db.execute(
        select(sqlfunc.count()).select_from(ChatSession)
    )).scalar() or 0

    active_sessions = (await db.execute(
        select(sqlfunc.count()).select_from(ChatSession).where(ChatSession.status == "ACTIVE")
    )).scalar() or 0

    sr_created = (await db.execute(
        select(sqlfunc.count()).select_from(ChatSession)
        .where(ChatSession.created_sr_id.isnot(None))
    )).scalar() or 0

    total_messages = (await db.execute(
        select(sqlfunc.count()).select_from(ChatMessage)
    )).scalar() or 0

    return {
        "total_sessions":  total_sessions,
        "active_sessions": active_sessions,
        "sr_auto_created": sr_created,
        "total_messages":  total_messages,
        "sr_conversion_rate": round(sr_created / total_sessions * 100, 1) if total_sessions > 0 else 0,
    }
