"""
C-3: Problem Management API 라우터

엔드포인트:
  POST /api/problem/               — 문제 레코드 생성
  GET  /api/problem/               — 문제 목록
  GET  /api/problem/{prb_id}       — 문제 상세
  PATCH /api/problem/{prb_id}      — 문제 수정
  POST /api/problem/{prb_id}/rca   — RCA 기록
  POST /api/problem/{prb_id}/workaround — 임시 해결 기록
  POST /api/problem/{prb_id}/resolve   — 해결 처리
  POST /api/problem/{prb_id}/close     — 종결 처리
  POST /api/problem/{prb_id}/notes     — 활동 노트 추가
  GET  /api/problem/{prb_id}/notes     — 활동 노트 목록
  GET  /api/problem/known-errors       — Known Error DB
  GET  /api/problem/stats              — Problem 통계
"""
from __future__ import annotations

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

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

from core.auth import get_current_user
from database import get_db
from models import (
    User, UserRole,
    ProblemRecord, ProblemRecordOut, ProblemRecordCreate,
    ProblemNote, ProblemNoteCreate,
    ProblemStatus, ProblemCategory,
)

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


async def _next_problem_id(db: AsyncSession) -> str:
    today  = datetime.utcnow().strftime("%Y%m%d")
    prefix = f"PRB-{today}-"
    last   = (await db.execute(
        select(ProblemRecord.problem_id)
        .where(ProblemRecord.problem_id.like(f"{prefix}%"))
        .order_by(desc(ProblemRecord.problem_id)).limit(1)
    )).scalar()
    seq = 1 if not last else (int(last.split("-")[-1]) + 1 if last else 1)
    return f"{prefix}{seq:04d}"


async def _get_problem(db: AsyncSession, prb_id: str) -> ProblemRecord:
    prb = (await db.execute(
        select(ProblemRecord).where(ProblemRecord.problem_id == prb_id)
    )).scalars().first()
    if not prb:
        raise HTTPException(404, f"문제 레코드 {prb_id}를 찾을 수 없습니다.")
    return prb


@router.post("/", response_model=ProblemRecordOut, status_code=201)
async def create_problem(
    body: ProblemRecordCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """문제 레코드 생성."""
    problem_id = await _next_problem_id(db)
    prb = ProblemRecord(
        problem_id      = problem_id,
        title           = body.title,
        description     = body.description,
        status          = ProblemStatus.OPEN.value,
        priority        = body.priority.upper(),
        category        = body.category.upper(),
        related_sr_ids  = json.dumps(body.related_sr_ids or [], ensure_ascii=False),
        ci_id           = body.ci_id,
        affected_users  = body.affected_users,
        incident_count  = body.incident_count,
        total_downtime_min = body.total_downtime_min,
        created_by      = current_user.username,
    )
    db.add(prb)
    await db.commit()
    await db.refresh(prb)
    return prb


@router.get("/known-errors", response_model=List[ProblemRecordOut])
async def known_errors(
    limit: int = Query(20, ge=1, le=100),
    db: AsyncSession = Depends(get_db),
    _u: User = Depends(get_current_user),
):
    """Known Error DB 조회."""
    rows = (await db.execute(
        select(ProblemRecord)
        .where(ProblemRecord.known_error == True)
        .order_by(desc(ProblemRecord.updated_at))
        .limit(limit)
    )).scalars().all()
    return rows


@router.get("/stats")
async def problem_stats(
    days: int = Query(30, ge=1, le=365),
    db: AsyncSession = Depends(get_db),
    _u: User = Depends(get_current_user),
):
    """Problem 통계."""
    since = datetime.utcnow() - timedelta(days=days)
    total = (await db.execute(
        select(func.count()).select_from(ProblemRecord).where(ProblemRecord.created_at >= since)
    )).scalar() or 0

    by_status = {}
    for st, cnt in (await db.execute(
        select(ProblemRecord.status, func.count())
        .where(ProblemRecord.created_at >= since)
        .group_by(ProblemRecord.status)
    )).all():
        by_status[st] = cnt

    known_err_count = (await db.execute(
        select(func.count()).select_from(ProblemRecord)
        .where(ProblemRecord.known_error == True)
    )).scalar() or 0

    return {
        "period_days":    days,
        "total":          total,
        "by_status":      by_status,
        "known_errors":   known_err_count,
        "open":           by_status.get("OPEN", 0),
        "investigating":  by_status.get("INVESTIGATING", 0),
        "rca_done":       by_status.get("RCA_DONE", 0),
    }


@router.get("/", response_model=List[ProblemRecordOut])
async def list_problems(
    status:   Optional[str] = Query(None),
    priority: Optional[str] = Query(None),
    category: Optional[str] = Query(None),
    limit:    int = Query(20, ge=1, le=100),
    offset:   int = Query(0, ge=0),
    db: AsyncSession = Depends(get_db),
    _u: User = Depends(get_current_user),
):
    """문제 레코드 목록."""
    conditions = []
    if status:   conditions.append(ProblemRecord.status   == status.upper())
    if priority: conditions.append(ProblemRecord.priority == priority.upper())
    if category: conditions.append(ProblemRecord.category == category.upper())

    q = select(ProblemRecord)
    if conditions:
        q = q.where(and_(*conditions))
    q = q.order_by(desc(ProblemRecord.created_at)).limit(limit).offset(offset)
    return (await db.execute(q)).scalars().all()


@router.get("/{prb_id}", response_model=ProblemRecordOut)
async def get_problem(prb_id: str, db: AsyncSession = Depends(get_db), _u: User = Depends(get_current_user)):
    return await _get_problem(db, prb_id)


@router.patch("/{prb_id}", response_model=ProblemRecordOut)
async def update_problem(
    prb_id: str,
    body: dict = Body(...),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """문제 레코드 수정."""
    prb = await _get_problem(db, prb_id)
    for k, v in body.items():
        if hasattr(prb, k) and k not in ("id", "problem_id", "created_at"):
            setattr(prb, k, v)
    await db.commit()
    await db.refresh(prb)
    return prb


@router.post("/{prb_id}/rca")
async def record_rca(
    prb_id: str,
    root_cause: str = Body(..., embed=True),
    permanent_fix: Optional[str] = Body(None, embed=True),
    known_error: bool = Body(False, embed=True),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """RCA (근본 원인 분석) 기록."""
    prb = await _get_problem(db, prb_id)
    prb.root_cause        = root_cause
    prb.permanent_fix     = permanent_fix
    prb.known_error       = known_error
    prb.status            = ProblemStatus.RCA_DONE.value
    prb.rca_completed_at  = datetime.utcnow()

    note = ProblemNote(
        problem_id_fk = prb.id,
        note_type     = "RCA",
        content       = f"RCA 완료: {root_cause[:200]}",
        author        = current_user.username,
    )
    db.add(note)
    await db.commit()
    return {"problem_id": prb_id, "status": prb.status, "known_error": known_error}


@router.post("/{prb_id}/workaround")
async def record_workaround(
    prb_id: str,
    workaround: str = Body(..., embed=True),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """임시 해결 방법 기록."""
    prb = await _get_problem(db, prb_id)
    prb.workaround = workaround
    if prb.status not in (ProblemStatus.RESOLVED.value, ProblemStatus.CLOSED.value):
        prb.status = ProblemStatus.WORKAROUND.value

    note = ProblemNote(
        problem_id_fk = prb.id,
        note_type     = "WORKAROUND",
        content       = f"임시 해결책: {workaround[:200]}",
        author        = current_user.username,
    )
    db.add(note)
    await db.commit()
    return {"problem_id": prb_id, "status": prb.status}


@router.post("/{prb_id}/resolve")
async def resolve_problem(
    prb_id: str,
    resolution: Optional[str] = Body(None, embed=True),
    rfc_id: Optional[str] = Body(None, embed=True),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """문제 해결 처리."""
    prb = await _get_problem(db, prb_id)
    prb.status      = ProblemStatus.RESOLVED.value
    prb.resolved_at = datetime.utcnow()
    if resolution:  prb.permanent_fix = resolution
    if rfc_id:      prb.rfc_id = rfc_id

    note = ProblemNote(
        problem_id_fk = prb.id,
        note_type     = "RESOLUTION",
        content       = resolution or "문제 해결 완료",
        author        = current_user.username,
    )
    db.add(note)
    await db.commit()
    return {"problem_id": prb_id, "status": prb.status}


@router.post("/{prb_id}/close")
async def close_problem(
    prb_id: str,
    note_text: Optional[str] = Body(None, embed=True),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """문제 종결 처리."""
    prb = await _get_problem(db, prb_id)
    if prb.status != ProblemStatus.RESOLVED.value:
        raise HTTPException(400, f"RESOLVED 상태가 아닙니다: {prb.status}")
    prb.status    = ProblemStatus.CLOSED.value
    prb.closed_at = datetime.utcnow()
    await db.commit()
    return {"problem_id": prb_id, "status": prb.status}


@router.post("/{prb_id}/notes")
async def add_note(
    prb_id: str,
    body: ProblemNoteCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """활동 노트 추가."""
    prb = await _get_problem(db, prb_id)
    if prb.status == ProblemStatus.INVESTIGATING.value or prb.status == ProblemStatus.OPEN.value:
        prb.status = ProblemStatus.INVESTIGATING.value
    note = ProblemNote(
        problem_id_fk = prb.id,
        note_type     = body.note_type.upper(),
        content       = body.content,
        author        = current_user.username,
    )
    db.add(note)
    await db.commit()
    return {"ok": True, "note_type": body.note_type}


@router.get("/{prb_id}/notes")
async def get_notes(
    prb_id: str,
    db: AsyncSession = Depends(get_db),
    _u: User = Depends(get_current_user),
):
    """활동 노트 목록."""
    prb = await _get_problem(db, prb_id)
    notes = (await db.execute(
        select(ProblemNote)
        .where(ProblemNote.problem_id_fk == prb.id)
        .order_by(ProblemNote.created_at)
    )).scalars().all()
    return [
        {"id": n.id, "note_type": n.note_type, "content": n.content,
         "author": n.author, "created_at": n.created_at.isoformat()}
        for n in notes
    ]


# ── G-5: 자동 RCA 분석 ────────────────────────────────────────────────────────

@router.post("/{prb_id}/auto-rca")
async def auto_rca_problem(
    prb_id: str,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Ollama LLM으로 Problem RCA 초안 자동 생성 후 레코드에 저장."""
    prb = await _get_problem(db, prb_id)
    try:
        from core.auto_rca import analyze_problem_rca
        result = await analyze_problem_rca(prb.id, db)
    except Exception as e:
        raise HTTPException(500, f"RCA 분석 오류: {str(e)[:200]}")

    rca_data = result["rca"]
    prb.root_cause = rca_data.get("root_cause", "")
    prb.permanent_fix = json.dumps(rca_data.get("prevention", []), ensure_ascii=False)
    prb.rca_completed_at = datetime.utcnow()
    prb.updated_at = datetime.utcnow()
    await db.commit()
    return result
