"""Journal Club API：文献排队 + 排期 + 会议记录 + 归档 + 考勤 + 统计"""

import uuid
from datetime import date, datetime

from typing import Literal

from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel, Field
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession

from app.compat import UTC
from app.core.permissions import get_current_user
from app.core.tenant_context import tenant_ctx
from app.db import get_db
from app.models.literature import GlobalLiterature
from app.models.team import JournalClubQueue, JournalClubAttendance
from app.models.user import User

router = APIRouter()


def uid(u: dict) -> uuid.UUID:
    return uuid.UUID(u["sub"])


class JCCreate(BaseModel):
    literature_pmid: int
    title: str | None = None
    scheduled_date: str | None = None  # YYYY-MM-DD
    presenter_id: str | None = None


class JCDecision(BaseModel):
    status: Literal["presented", "skipped"]  # presented | skipped
    discussion_notes: str | None = None


class JCUpdate(BaseModel):
    scheduled_date: str | None = None
    presenter_id: str | None = None


class JCAttendanceUpsert(BaseModel):
    rating: int | None = Field(default=None, ge=1, le=5)
    comment: str | None = None


# ── /stats ──


@router.get("/stats", summary="统计数据")
async def get_stats(
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
):
    """返回排队数量、本月汇报、归档总数、月度趋势、热门汇报人"""
    tid = tenant_ctx.get()
    if not tid:
        return {"queued_count": 0, "presented_this_month": 0, "total_archived": 0, "monthly_counts": [], "top_presenters": []}
    tid_uuid = uuid.UUID(tid)

    # 排队数量
    queued_count = (await db.execute(
        select(func.count(JournalClubQueue.id))
        .where(JournalClubQueue.tenant_id == tid_uuid, JournalClubQueue.status == "queued")
    )).scalar() or 0

    # 本月已汇报
    now = datetime.now(UTC)
    first_of_month = date(now.year, now.month, 1)
    presented_this_month = (await db.execute(
        select(func.count(JournalClubQueue.id))
        .where(
            JournalClubQueue.tenant_id == tid_uuid,
            JournalClubQueue.status == "presented",
            JournalClubQueue.scheduled_date >= first_of_month,
        )
    )).scalar() or 0

    # 总归档数
    total_archived = (await db.execute(
        select(func.count(JournalClubQueue.id))
        .where(
            JournalClubQueue.tenant_id == tid_uuid,
            JournalClubQueue.status.in_(["presented", "skipped"]),
        )
    )).scalar() or 0

    # 月度统计（近 6 个月）
    month = now.month - 5
    year = now.year
    while month < 1:
        month += 12
        year -= 1
    six_months_ago = date(year, month, 1)

    month_label = func.to_char(JournalClubQueue.scheduled_date, "YYYY-MM").label("month")
    count_label = func.count(JournalClubQueue.id).label("cnt")
    monthly_rows = (await db.execute(
        select(month_label, count_label)
        .where(
            JournalClubQueue.tenant_id == tid_uuid,
            JournalClubQueue.status == "presented",
            JournalClubQueue.scheduled_date >= six_months_ago,
        )
        .group_by(month_label)
        .order_by(month_label)
    )).all()
    monthly_counts = [{"month": r.month, "count": r.cnt} for r in monthly_rows]

    # 热门汇报人（top 5）
    top_rows = (await db.execute(
        select(
            JournalClubQueue.presenter_id,
            User.display_name,
            func.count(JournalClubQueue.id).label("cnt"),
        )
        .outerjoin(User, User.id == JournalClubQueue.presenter_id)
        .where(
            JournalClubQueue.tenant_id == tid_uuid,
            JournalClubQueue.status == "presented",
            JournalClubQueue.presenter_id.isnot(None),
        )
        .group_by(JournalClubQueue.presenter_id, User.display_name)
        .order_by(func.count(JournalClubQueue.id).desc())
        .limit(5)
    )).all()
    top_presenters = [
        {"presenter_id": str(r.presenter_id), "display_name": r.display_name, "count": r.cnt}
        for r in top_rows
    ]

    return {
        "queued_count": queued_count,
        "presented_this_month": presented_this_month,
        "total_archived": total_archived,
        "monthly_counts": monthly_counts,
        "top_presenters": top_presenters,
    }


# ── /queue ──


@router.get("/queue", summary="排队列表")
async def list_queue(
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
):
    tid = tenant_ctx.get()
    if not tid:
        return {"items": [], "total": 0}
    tid_uuid = uuid.UUID(tid)
    offset = (page - 1) * page_size
    total = (await db.execute(
        select(func.count(JournalClubQueue.id)).where(JournalClubQueue.tenant_id == tid_uuid)
    )).scalar() or 0
    result = await db.execute(
        select(JournalClubQueue, GlobalLiterature)
        .join(GlobalLiterature, JournalClubQueue.literature_id == GlobalLiterature.id)
        .where(JournalClubQueue.tenant_id == tid_uuid)
        .order_by(JournalClubQueue.status.asc(), JournalClubQueue.scheduled_date.desc().nullslast())
        .offset(offset).limit(page_size)
    )
    items = []
    for jc, lit in result:
        items.append({
            "id": str(jc.id),
            "pmid": lit.pmid,
            "title": jc.title or lit.title,
            "journal": lit.journal,
            "scheduled_date": jc.scheduled_date.isoformat() if jc.scheduled_date else None,
            "presenter_id": str(jc.presenter_id) if jc.presenter_id else None,
            "status": jc.status,
            "discussion_notes": jc.discussion_notes,
            "suggested_by": str(jc.suggested_by),
            "created_at": jc.created_at.isoformat() if jc.created_at else None,
        })
    return {"items": items, "total": total}


@router.post("/queue", summary="加入排队")
async def add_to_queue(
    req: JCCreate,
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
):
    tid = tenant_ctx.get()
    if not tid:
        return {"status": "skipped", "note": "请先创建或加入团队"}
    lit = (await db.execute(select(GlobalLiterature).where(GlobalLiterature.pmid == req.literature_pmid))).scalar()
    if not lit:
        raise HTTPException(404, detail=f"PMID {req.literature_pmid} 没有找到")
    sd = date.fromisoformat(req.scheduled_date) if req.scheduled_date else None
    jc = JournalClubQueue(
        id=uuid.uuid4(),
        tenant_id=uuid.UUID(tid),
        literature_id=lit.id,
        suggested_by=uid(user),
        title=req.title,
        scheduled_date=sd,
        presenter_id=uuid.UUID(req.presenter_id) if req.presenter_id else None,
        status="queued",
    )
    db.add(jc)
    await db.commit()
    return {"status": "queued", "id": str(jc.id)}


@router.post("/queue/{jid}/decide", summary="评议文献")
async def decide_article(
    jid: str,
    req: JCDecision,
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
):
    tid = tenant_ctx.get()
    if not tid:
        return {"status": "skipped", "note": "请先创建或加入团队"}
    tid_uuid = uuid.UUID(tid)
    jc = (await db.execute(
        select(JournalClubQueue).where(
            JournalClubQueue.id == uuid.UUID(jid),
            JournalClubQueue.tenant_id == tid_uuid,
        )
    )).scalar()
    if not jc:
        raise HTTPException(404)
    jc.status = req.status
    if req.discussion_notes:
        jc.discussion_notes = req.discussion_notes
    jc.updated_at = datetime.now(UTC)
    await db.commit()
    return {"status": "updated"}


class JCNotes(BaseModel):
    discussion_notes: str


@router.post("/queue/{jid}/notes", summary="更新会议笔记")
async def update_notes(
    jid: str,
    req: JCNotes,
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
):
    """更新已汇报文献的讨论笔记"""
    tid = tenant_ctx.get()
    if not tid:
        return {"status": "skipped", "note": "请先创建或加入团队"}
    tid_uuid = uuid.UUID(tid)
    jc = (await db.execute(
        select(JournalClubQueue).where(
            JournalClubQueue.id == uuid.UUID(jid),
            JournalClubQueue.tenant_id == tid_uuid,
        )
    )).scalar()
    if not jc:
        raise HTTPException(404)
    jc.discussion_notes = req.discussion_notes
    jc.updated_at = datetime.now(UTC)
    await db.commit()
    return {"status": "updated"}


@router.delete("/queue/{jid}", summary="移除排队")
async def remove_from_queue(
    jid: str,
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
):
    tid = tenant_ctx.get()
    if not tid:
        return {"status": "skipped", "note": "请先创建或加入团队"}
    tid_uuid = uuid.UUID(tid)
    jc = (await db.execute(
        select(JournalClubQueue).where(
            JournalClubQueue.id == uuid.UUID(jid),
            JournalClubQueue.tenant_id == tid_uuid,
        )
    )).scalar()
    if not jc:
        raise HTTPException(404)
    await db.delete(jc)
    await db.commit()
    return {"status": "deleted"}


@router.patch("/queue/{jid}", summary="更新排期/汇报人")
async def update_queue_item(
    jid: str,
    req: JCUpdate,
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
):
    tid = tenant_ctx.get()
    if not tid:
        return {"status": "skipped", "note": "请先创建或加入团队"}
    tid_uuid = uuid.UUID(tid)
    jc = (await db.execute(
        select(JournalClubQueue).where(
            JournalClubQueue.id == uuid.UUID(jid),
            JournalClubQueue.tenant_id == tid_uuid,
        )
    )).scalar()
    if not jc:
        raise HTTPException(404)
    if req.scheduled_date is not None:
        jc.scheduled_date = date.fromisoformat(req.scheduled_date) if req.scheduled_date else None
    if req.presenter_id is not None:
        jc.presenter_id = uuid.UUID(req.presenter_id) if req.presenter_id else None
    jc.updated_at = datetime.now(UTC)
    await db.commit()
    return {"status": "updated"}


# ── /attendance ──


@router.post("/queue/{jid}/attendance", summary="记录参会")
async def upsert_attendance(
    jid: str,
    req: JCAttendanceUpsert,
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
):
    """记录/更新参会信息（upsert by queue_id + user_id）"""
    tid = tenant_ctx.get()
    if not tid:
        return {"status": "skipped", "note": "请先创建或加入团队"}
    tid_uuid = uuid.UUID(tid)
    q_uuid = uuid.UUID(jid)

    # 验证 queue 项存在且属于当前租户
    jc = (await db.execute(
        select(JournalClubQueue).where(
            JournalClubQueue.id == q_uuid,
            JournalClubQueue.tenant_id == tid_uuid,
        )
    )).scalar()
    if not jc:
        raise HTTPException(404)

    existing = (await db.execute(
        select(JournalClubAttendance).where(
            JournalClubAttendance.queue_id == q_uuid,
            JournalClubAttendance.user_id == uid(user),
        )
    )).scalar()

    if existing:
        existing.rating = req.rating
        existing.comment = req.comment
    else:
        att = JournalClubAttendance(
            id=uuid.uuid4(),
            tenant_id=tid_uuid,
            queue_id=q_uuid,
            user_id=uid(user),
            attended=True,
            rating=req.rating,
            comment=req.comment,
        )
        db.add(att)
    await db.commit()
    return {"status": "recorded"}


@router.get("/queue/{jid}/attendance", summary="参会列表")
async def list_attendance(
    jid: str,
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
):
    tid = tenant_ctx.get()
    if not tid:
        return {"attendees": []}
    tid_uuid = uuid.UUID(tid)
    q_uuid = uuid.UUID(jid)

    jc = (await db.execute(
        select(JournalClubQueue).where(
            JournalClubQueue.id == q_uuid,
            JournalClubQueue.tenant_id == tid_uuid,
        )
    )).scalar()
    if not jc:
        raise HTTPException(404)

    rows = (await db.execute(
        select(JournalClubAttendance, User.display_name)
        .join(User, User.id == JournalClubAttendance.user_id)
        .where(JournalClubAttendance.queue_id == q_uuid)
        .order_by(JournalClubAttendance.created_at)
    )).all()
    attendees = [
        {
            "id": str(att.id),
            "user_id": str(att.user_id),
            "display_name": display_name,
            "attended": att.attended,
            "rating": att.rating,
            "comment": att.comment,
            "created_at": att.created_at.isoformat() if att.created_at else None,
        }
        for att, display_name in rows
    ]
    return {"attendees": attendees}


@router.delete("/queue/{jid}/attendance", summary="取消参会")
async def remove_attendance(
    jid: str,
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
):
    tid = tenant_ctx.get()
    if not tid:
        return {"status": "skipped", "note": "请先创建或加入团队"}
    tid_uuid = uuid.UUID(tid)
    q_uuid = uuid.UUID(jid)

    jc = (await db.execute(
        select(JournalClubQueue).where(
            JournalClubQueue.id == q_uuid,
            JournalClubQueue.tenant_id == tid_uuid,
        )
    )).scalar()
    if not jc:
        raise HTTPException(404)

    att = (await db.execute(
        select(JournalClubAttendance).where(
            JournalClubAttendance.queue_id == q_uuid,
            JournalClubAttendance.user_id == uid(user),
        )
    )).scalar()
    if not att:
        raise HTTPException(404)

    await db.delete(att)
    await db.commit()
    return {"status": "deleted"}


# ── /archive ──


@router.get("/archive", summary="归档列表")
async def list_archive(
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
):
    tid = tenant_ctx.get()
    if not tid:
        return {"items": [], "total": 0}
    tid_uuid = uuid.UUID(tid)
    offset = (page - 1) * page_size
    total = (await db.execute(
        select(func.count(JournalClubQueue.id))
        .where(
            JournalClubQueue.tenant_id == tid_uuid,
            JournalClubQueue.status.in_(["presented", "skipped"]),
        )
    )).scalar() or 0
    result = await db.execute(
        select(JournalClubQueue, GlobalLiterature, User.display_name.label("presenter_name"))
        .join(GlobalLiterature, JournalClubQueue.literature_id == GlobalLiterature.id)
        .outerjoin(User, User.id == JournalClubQueue.presenter_id)
        .where(
            JournalClubQueue.tenant_id == tid_uuid,
            JournalClubQueue.status.in_(["presented", "skipped"]),
        )
        .order_by(JournalClubQueue.scheduled_date.desc().nullslast())
        .offset(offset).limit(page_size)
    )
    items = [
        {
            "id": str(jc.id),
            "pmid": lit.pmid,
            "title": jc.title or lit.title,
            "journal": lit.journal,
            "status": jc.status,
            "discussion_notes": jc.discussion_notes,
            "scheduled_date": jc.scheduled_date.isoformat() if jc.scheduled_date else None,
            "presenter_name": presenter_name,
        }
        for jc, lit, presenter_name in result
    ]
    return {"items": items, "total": total}


# ── AI Outline & Preread ──


@router.get("/ai-outline/{pmid}", summary="生成提纲")
async def generate_outline(
    pmid: int,
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
):
    """AI 生成 Journal Club 汇报提纲"""
    lit = (await db.execute(select(GlobalLiterature).where(GlobalLiterature.pmid == pmid))).scalar()
    if not lit:
        raise HTTPException(404)
    if not lit.abstract:
        raise HTTPException(400, "No abstract available")
    from app.services.ai_summary import generate_structured_summary

    summary = await generate_structured_summary(lit.title, lit.abstract)
    outline = f"""# Journal Club 汇报提纲

## \U0001f4cb 文献信息
- 标题：{lit.title}
- 期刊：{lit.journal}（{lit.pub_year}）
- PMID：{lit.pmid}

## \U0001f52c 研究背景
（由 AI 生成）

## \U0001f3af 研究目的
（由 AI 生成）

## \U0001f4ca 方法设计
（由 AI 生成）

## \U0001f4c8 主要结果
（由 AI 生成）

## \U0001f4a1 讨论要点
1. 这项研究的设计有什么优缺点？
2. 结果是否适用于我们的临床实践？
3. 与现行指南/标准治疗相比如何？

## \U0001f3e5 临床意义
（由 AI 生成）

---
*AI 摘要：{summary or '生成中...'}*
"""
    return {"pmid": pmid, "outline": outline}


@router.get("/preread/{pmid}", summary="读前必读推荐")
async def preread_recommendations(
    pmid: int,
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
):
    """根据标签重叠 + 引用关系推荐该篇文献的前置阅读文献"""
    from app.api.v1.literature import _get_related_literature

    lit = (await db.execute(select(GlobalLiterature).where(GlobalLiterature.pmid == pmid))).scalar()
    if not lit:
        raise HTTPException(404)
    items, source = await _get_related_literature(db, lit, limit=5)
    return {"items": items, "source": source}
