"""
Self-Improving Learning Loop — API Router

엔드포인트:
  GET  /api/learning/stats                   — 학습 현황 통계
  GET  /api/learning/patterns                — 재발 패턴 목록
  GET  /api/learning/patterns/{id}           — 패턴 상세
  GET  /api/learning/lessons                 — 검증된 교훈 목록
  GET  /api/learning/thresholds              — 적응형 임계값 현황
  POST /api/learning/feedback                — KB 사용 피드백 기록
  POST /api/learning/feedback/{id}/check     — 피드백 효과 즉시 검증
  POST /api/learning/thresholds/outcome      — 이상 탐지 결과 기록
  POST /api/learning/thresholds/missed       — 누락 탐지 기록
  POST /api/learning/thresholds/calibrate    — 임계값 즉시 보정
  POST /api/learning/mine                    — 패턴 마이닝 즉시 실행
  POST /api/learning/detect-recurrence       — SR 재발 감지 (수동 호출)
"""
from datetime import datetime
from typing import List, Optional

from fastapi import APIRouter, Depends, Query
from pydantic import BaseModel
from sqlalchemy import select, desc
from sqlalchemy.ext.asyncio import AsyncSession

from core.auth import get_current_user
from database import get_db
from models import (
    RecurrencePattern, SolutionFeedback, AdaptiveThreshold, LessonLearned, User
)

router = APIRouter(prefix="/api/learning", tags=["learning"])


# ── Pydantic I/O ───────────────────────────────────────────────────────────────

class FeedbackCreate(BaseModel):
    sr_id:     str
    kb_doc_id: str
    kb_id:     Optional[int] = None

class OutcomeRecord(BaseModel):
    source:              str
    metric_type:         str
    was_actual_incident: bool
    base_threshold:      Optional[float] = None

class MissedRecord(BaseModel):
    source:      str
    metric_type: str

class CalibrateRequest(BaseModel):
    source:      str
    metric_type: str

class RecurrenceRequest(BaseModel):
    sr_id:       str
    title:       str
    description: str
    sr_type:     str
    inst_id:     Optional[int] = None

class MineRequest(BaseModel):
    days_back:        int = 30
    min_occurrences:  int = 3


# ── 통계 요약 ──────────────────────────────────────────────────────────────────

@router.get("/stats")
async def get_stats(
    db: AsyncSession = Depends(get_db),
    _: User = Depends(get_current_user),
):
    from core.learning import get_learning_stats
    return await get_learning_stats(db)


# ── 재발 패턴 ──────────────────────────────────────────────────────────────────

@router.get("/patterns")
async def list_patterns(
    limit:   int = Query(50, le=200),
    offset:  int = Query(0, ge=0),
    sr_type: Optional[str] = None,
    escalated_only: bool = False,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(get_current_user),
):
    q = select(RecurrencePattern)
    if sr_type:
        q = q.where(RecurrencePattern.sr_type == sr_type)
    if escalated_only:
        q = q.where(RecurrencePattern.escalated == True)
    q = q.order_by(desc(RecurrencePattern.occurrence_count)).offset(offset).limit(limit)
    rows = (await db.execute(q)).scalars().all()

    return [
        {
            "id":               p.id,
            "sr_type":          p.sr_type,
            "tech_keywords":    p.tech_keywords,
            "occurrence_count": p.occurrence_count,
            "first_seen_at":    p.first_seen_at.isoformat() if p.first_seen_at else None,
            "last_seen_at":     p.last_seen_at.isoformat() if p.last_seen_at else None,
            "escalated":        p.escalated,
            "problem_id":       p.problem_id,
            "sr_ids":           (p.sr_ids or [])[-5:],
        }
        for p in rows
    ]


@router.get("/patterns/{pattern_id}")
async def get_pattern(
    pattern_id: int,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(get_current_user),
):
    p = (await db.execute(
        select(RecurrencePattern).where(RecurrencePattern.id == pattern_id)
    )).scalars().first()
    if not p:
        from fastapi import HTTPException
        raise HTTPException(status_code=404, detail="패턴을 찾을 수 없습니다")

    return {
        "id":               p.id,
        "pattern_key":      p.pattern_key,
        "sr_type":          p.sr_type,
        "inst_id":          p.inst_id,
        "keyword_signature": p.keyword_signature,
        "tech_keywords":    p.tech_keywords,
        "occurrence_count": p.occurrence_count,
        "first_seen_at":    p.first_seen_at.isoformat() if p.first_seen_at else None,
        "last_seen_at":     p.last_seen_at.isoformat() if p.last_seen_at else None,
        "escalated":        p.escalated,
        "problem_id":       p.problem_id,
        "sr_ids":           p.sr_ids or [],
    }


# ── 재발 감지 ──────────────────────────────────────────────────────────────────

@router.post("/detect-recurrence")
async def detect_recurrence(
    body: RecurrenceRequest,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(get_current_user),
):
    from core.learning import detect_recurrence as _detect
    return await _detect(
        db          = db,
        sr_id       = body.sr_id,
        title       = body.title,
        description = body.description,
        sr_type     = body.sr_type,
        inst_id     = body.inst_id,
    )


# ── 솔루션 효과 피드백 ─────────────────────────────────────────────────────────

@router.post("/feedback")
async def create_feedback(
    body: FeedbackCreate,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(get_current_user),
):
    from core.learning import record_kb_usage
    return await record_kb_usage(db, body.sr_id, body.kb_doc_id, body.kb_id)


@router.post("/feedback/{feedback_id}/check")
async def check_feedback(
    feedback_id: int,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(get_current_user),
):
    from core.learning import check_solution_effectiveness
    return await check_solution_effectiveness(db, feedback_id)


@router.get("/feedback")
async def list_feedback(
    limit:  int = Query(50, le=200),
    offset: int = Query(0, ge=0),
    db: AsyncSession = Depends(get_db),
    _: User = Depends(get_current_user),
):
    rows = (await db.execute(
        select(SolutionFeedback)
        .order_by(desc(SolutionFeedback.applied_at))
        .offset(offset).limit(limit)
    )).scalars().all()

    return [
        {
            "id":                   f.id,
            "sr_id":                f.sr_id,
            "kb_doc_id":            f.kb_doc_id,
            "applied_at":           f.applied_at.isoformat() if f.applied_at else None,
            "effectiveness_score":  f.effectiveness_score,
            "recurred_within_days": f.recurred_within_days,
            "checked_at":           f.checked_at.isoformat() if f.checked_at else None,
        }
        for f in rows
    ]


# ── 교훈 목록 ──────────────────────────────────────────────────────────────────

@router.get("/lessons")
async def list_lessons(
    limit:         int = Query(50, le=200),
    offset:        int = Query(0, ge=0),
    verified_only: bool = False,
    category:      Optional[str] = None,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(get_current_user),
):
    q = select(LessonLearned)
    if verified_only:
        q = q.where(LessonLearned.is_verified == True)
    if category:
        q = q.where(LessonLearned.category == category)
    q = q.order_by(desc(LessonLearned.confidence_score)).offset(offset).limit(limit)
    rows = (await db.execute(q)).scalars().all()

    return [
        {
            "id":               l.id,
            "lesson_id":        l.lesson_id,
            "title":            l.title,
            "category":         l.category,
            "problem_pattern":  l.problem_pattern,
            "root_cause":       l.root_cause,
            "effective_solution": l.effective_solution,
            "prevention":       l.prevention,
            "confidence_score": l.confidence_score,
            "is_verified":      l.is_verified,
            "created_at":       l.created_at.isoformat() if l.created_at else None,
        }
        for l in rows
    ]


# ── 적응형 임계값 ──────────────────────────────────────────────────────────────

@router.get("/thresholds")
async def list_thresholds(
    source:      Optional[str] = None,
    metric_type: Optional[str] = None,
    adapted_only: bool = False,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(get_current_user),
):
    q = select(AdaptiveThreshold)
    if source:
        q = q.where(AdaptiveThreshold.source == source)
    if metric_type:
        q = q.where(AdaptiveThreshold.metric_type == metric_type)
    if adapted_only:
        q = q.where(AdaptiveThreshold.adaptation_count > 0)
    q = q.order_by(desc(AdaptiveThreshold.adaptation_count)).limit(200)
    rows = (await db.execute(q)).scalars().all()

    return [
        {
            "id":               t.id,
            "source":           t.source,
            "metric_type":      t.metric_type,
            "base_threshold":   t.base_threshold,
            "adapted_threshold": t.adapted_threshold,
            "change_pct": round(
                (t.adapted_threshold - t.base_threshold) / t.base_threshold * 100, 1
            ) if t.base_threshold else 0,
            "true_positive":    t.true_positive,
            "false_positive":   t.false_positive,
            "missed_count":     t.missed_count,
            "adaptation_count": t.adaptation_count,
            "last_adapted_at":  t.last_adapted_at.isoformat() if t.last_adapted_at else None,
        }
        for t in rows
    ]


@router.post("/thresholds/outcome")
async def record_outcome(
    body: OutcomeRecord,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(get_current_user),
):
    from core.learning import record_anomaly_outcome
    return await record_anomaly_outcome(
        db, body.source, body.metric_type,
        body.was_actual_incident, body.base_threshold,
    )


@router.post("/thresholds/missed")
async def record_missed(
    body: MissedRecord,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(get_current_user),
):
    from core.learning import record_missed_detection
    return await record_missed_detection(db, body.source, body.metric_type)


@router.post("/thresholds/calibrate")
async def calibrate(
    body: CalibrateRequest,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(get_current_user),
):
    from core.learning import calibrate_threshold
    return await calibrate_threshold(db, body.source, body.metric_type)


@router.post("/thresholds/calibrate-all")
async def calibrate_all(
    db: AsyncSession = Depends(get_db),
    _: User = Depends(get_current_user),
):
    """모든 적응형 임계값 일괄 보정."""
    rows = (await db.execute(select(AdaptiveThreshold))).scalars().all()
    results = []
    from core.learning import calibrate_threshold
    for rec in rows:
        r = await calibrate_threshold(db, rec.source, rec.metric_type)
        if r.get("adjusted"):
            results.append(r)
    return {"calibrated": len(results), "results": results}


# ── 패턴 마이닝 ────────────────────────────────────────────────────────────────

@router.post("/mine")
async def mine_lessons(
    body: MineRequest,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(get_current_user),
):
    from core.learning import run_lesson_mining
    return await run_lesson_mining(db, body.days_back, body.min_occurrences)
