"""用户设置：评分 + 个人标签 + 反馈 + 学术画像"""

import uuid
from datetime import datetime, timedelta

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

from app.compat import UTC
from app.core.permissions import get_current_user, require_platform_operator
from app.db import get_db
from app.models.interaction import UserActivityLog, UserFeed, UserFeedback, UserFolder, UserLiterature, UserNote, UserSubscription
from app.models.user import User
from app.services.email_service import send_email

router = APIRouter()

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


class RatingRequest(BaseModel):
    rating: int = Field(..., ge=1, le=5)

class TagRequest(BaseModel):
    tag: str

class FeedbackRequest(BaseModel):
    feedback_type: str = "suggestion"
    detail: str

class FolderCreate(BaseModel):
    name: str
    description: str | None = None
    color: str | None = "#808080"

class FolderUpdate(BaseModel):
    name: str | None = None
    description: str | None = None
    color: str | None = None
    sort_order: int | None = None


@router.post("/literature/{pmid}/rate", summary="评分文献")
async def rate_literature(pmid: int, req: RatingRequest, db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user)):
    from app.models.literature import GlobalLiterature
    lit = (await db.execute(select(GlobalLiterature.id).where(GlobalLiterature.pmid == pmid))).scalar()
    if not lit: raise HTTPException(404)
    ul = (await db.execute(select(UserLiterature).where(UserLiterature.user_id == uid(user), UserLiterature.literature_id == lit))).scalar()
    if not ul:
        # 未收藏则自动收藏再评分
        ul = UserLiterature(user_id=uid(user), literature_id=lit)
        db.add(ul)
    ul.rating = min(5, max(1, req.rating))
    await db.commit()
    return {"status": "rated", "rating": ul.rating}

@router.post("/literature/{pmid}/tag", summary="个人标签")
async def add_personal_tag(pmid: int, req: TagRequest, db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user)):
    from app.models.literature import GlobalLiterature
    lit = (await db.execute(select(GlobalLiterature.id).where(GlobalLiterature.pmid == pmid))).scalar()
    if not lit: raise HTTPException(404)
    ul = (await db.execute(select(UserLiterature).where(UserLiterature.user_id == uid(user), UserLiterature.literature_id == lit))).scalar()
    if not ul: raise HTTPException(400, detail="Save first")
    tags = list(ul.personal_tags or [])
    tags.append({"name": req.tag, "added_at": datetime.now(UTC).isoformat()})
    ul.personal_tags = tags
    await db.commit()
    return {"status": "tagged", "personal_tags": tags}

@router.delete("/literature/{pmid}/tag", summary="删除标签")
async def remove_personal_tag(pmid: int, tag_name: str = "", db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user)):
    from app.models.literature import GlobalLiterature
    lit = (await db.execute(select(GlobalLiterature.id).where(GlobalLiterature.pmid == pmid))).scalar()
    if not lit: raise HTTPException(404)
    ul = (await db.execute(select(UserLiterature).where(UserLiterature.user_id == uid(user), UserLiterature.literature_id == lit))).scalar()
    if not ul: raise HTTPException(400)
    tags = list(ul.personal_tags or [])
    ul.personal_tags = [t for t in tags if t.get("name") != tag_name]
    await db.commit()
    return {"status": "removed"}

@router.post("/feedback", summary="提交反馈")
async def submit_feedback(req: FeedbackRequest, db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user)):
    fb = UserFeedback(user_id=uid(user), literature_id=None, feedback_type=req.feedback_type, detail=req.detail)
    db.add(fb); await db.commit()

    # 异步发邮件通知管理员
    user_uuid = uid(user)
    user_row = (await db.execute(select(User).where(User.id == user_uuid))).scalar()
    user_label = f"{user_row.display_name} ({user_row.email})" if user_row else str(user_uuid)
    html_body = f"""<div style="font-family:sans-serif;max-width:600px;margin:0 auto">
<h2 style="color:#1a5276">📬 新反馈通知</h2>
<p><strong>反馈人：</strong>{user_label}</p>
<p><strong>类型：</strong>{req.feedback_type}</p>
<p><strong>内容：</strong></p>
<blockquote style="padding:12px;background:#f5f7fa;border-left:4px solid #1a5276;margin:0">{req.detail}</blockquote>
<p style="color:#999;font-size:12px;margin-top:24px">OncoLit 反馈系统 · 自动发送</p>
</div>"""
    await send_email("326030087@qq.com", f"[OncoLit 反馈] {req.feedback_type}", html_body)

    return {"status": "received", "id": str(fb.id)}

@router.get("/feedback", summary="反馈列表")
async def list_feedback(
    _op: dict = Depends(require_platform_operator),
    db: AsyncSession = Depends(get_db),
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
):
    offset = (page - 1) * page_size
    total = (await db.execute(select(func.count(UserFeedback.id)))).scalar() or 0
    result = await db.execute(select(UserFeedback).order_by(UserFeedback.created_at.desc()).offset(offset).limit(page_size))
    items = result.scalars().all()
    return {"total": total, "items": [{"id": str(f.id), "user_id": str(f.user_id), "type": f.feedback_type, "detail": f.detail, "resolved": f.is_resolved, "created_at": f.created_at.isoformat() if f.created_at else None} for f in items]}

@router.post("/feedback/{fid}/resolve", summary="标记反馈已处理")
async def resolve_feedback(fid: str, _op: dict = Depends(require_platform_operator), db: AsyncSession = Depends(get_db)):
    fb = (await db.execute(select(UserFeedback).where(UserFeedback.id == uuid.UUID(fid)))).scalar()
    if not fb: raise HTTPException(404)
    fb.is_resolved = True
    await db.commit()
    return {"status": "resolved"}

@router.delete("/feedback/{fid}", summary="删除反馈")
async def delete_feedback(fid: str, _op: dict = Depends(require_platform_operator), db: AsyncSession = Depends(get_db)):
    fb = (await db.execute(select(UserFeedback).where(UserFeedback.id == uuid.UUID(fid)))).scalar()
    if not fb: raise HTTPException(404)
    await db.delete(fb)
    await db.commit()
    return {"status": "deleted"}


# ─── 个人文件夹 ───


@router.get("/folders", summary="文件夹列表（含文献数）")
async def list_folders(db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user)):
    user_uuid = uid(user)
    result = await db.execute(
        select(UserFolder, func.count(UserLiterature.id).label("cnt"))
        .outerjoin(UserLiterature, UserLiterature.folder_id == UserFolder.id)
        .where(UserFolder.user_id == user_uuid, UserFolder.is_shared == False)
        .group_by(UserFolder.id)
        .order_by(UserFolder.sort_order, UserFolder.created_at)
    )
    return {"items": [{
        "id": str(f.id), "name": f.name, "description": f.description,
        "color": f.color, "sort_order": f.sort_order, "article_count": cnt,
        "created_at": f.created_at.isoformat() if f.created_at else None,
    } for f, cnt in result]}


@router.post("/folders", summary="创建文件夹")
async def create_folder(req: FolderCreate, db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user)):
    from app.core.tenant_context import tenant_ctx
    tid = tenant_ctx.get() or uuid.UUID(user.get("tid", ""))
    f = UserFolder(user_id=uid(user), tenant_id=tid, name=req.name,
                   description=req.description, color=req.color or "#808080")
    db.add(f); await db.commit(); await db.refresh(f)
    return {"id": str(f.id), "name": f.name, "color": f.color}


@router.put("/folders/{fid}", summary="更新文件夹")
async def update_folder(fid: str, req: FolderUpdate, db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user)):
    f = (await db.execute(select(UserFolder).where(UserFolder.id == uuid.UUID(fid)))).scalar()
    if not f: raise HTTPException(404, "Folder not found")
    if f.user_id != uid(user): raise HTTPException(403, "Not your folder")
    if req.name is not None: f.name = req.name
    if req.description is not None: f.description = req.description
    if req.color is not None: f.color = req.color
    if req.sort_order is not None: f.sort_order = req.sort_order
    await db.commit()
    return {"status": "updated"}


@router.delete("/folders/{fid}", summary="删除文件夹（保留文献，移出文件夹）")
async def delete_folder(fid: str, db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user)):
    f = (await db.execute(select(UserFolder).where(UserFolder.id == uuid.UUID(fid)))).scalar()
    if not f: raise HTTPException(404, "Folder not found")
    if f.user_id != uid(user): raise HTTPException(403, "Not your folder")
    # 清除该文件夹下所有文献的 folder_id
    await db.execute(
        text("UPDATE user_literature SET folder_id = NULL WHERE folder_id = :fid AND user_id = :uid")
        .bindparams(fid=f.id, uid=uid(user))
    )
    await db.delete(f)
    await db.commit()
    return {"status": "deleted"}


# ─── 学术画像 ───

@router.get("/profile", summary="学术画像")
async def academic_profile(db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user)):
    """个人阅读报告 + 知识图谱数据"""
    user_uuid = uid(user)

    # 总收藏
    saved = (await db.execute(select(func.count(UserLiterature.id)).where(UserLiterature.user_id == user_uuid))).scalar() or 0
    # 已评分
    rated = (await db.execute(select(func.count(UserLiterature.id)).where(UserLiterature.user_id == user_uuid, UserLiterature.rating.isnot(None)))).scalar() or 0
    # 笔记数
    notes = (await db.execute(select(func.count(UserNote.id)).where(UserNote.user_id == user_uuid))).scalar() or 0
    # 订阅标签数
    subs = (await db.execute(select(func.count(UserSubscription.id)).where(UserSubscription.user_id == user_uuid, UserSubscription.is_active == True))).scalar() or 0
    # Feed 情况
    total_feed = (await db.execute(select(func.count(UserFeed.id)).where(UserFeed.user_id == user_uuid, UserFeed.is_dismissed == False))).scalar() or 0
    read_count = (await db.execute(select(func.count(UserFeed.id)).where(UserFeed.user_id == user_uuid, UserFeed.is_read == True))).scalar() or 0

    # 本周活跃天数
    week_ago = datetime.now(UTC) - timedelta(days=7)
    active_days = (await db.execute(select(func.count(UserFeed.id)).where(UserFeed.user_id == user_uuid, UserFeed.is_read == True, UserFeed.read_at >= week_ago))).scalar() or 0
    active_days = min(active_days, 7) if active_days else 0

    # 收藏期刊 Top 5
    from app.models.literature import GlobalLiterature
    j_result = await db.execute(
        select(GlobalLiterature.journal, func.count(GlobalLiterature.id).label("cnt"))
        .join(UserLiterature, UserLiterature.literature_id == GlobalLiterature.id)
        .where(UserLiterature.user_id == user_uuid)
        .group_by(GlobalLiterature.journal).order_by(text("cnt DESC")).limit(5)
    )
    top_journals = [{"journal": j or "Unknown", "count": c} for j, c in j_result]

    # 标签分布（从 Feed 的 matched_tags 中聚合）
    from app.models.literature import GlobalTag
    from collections import Counter

    feed_tags = await db.execute(
        select(UserFeed.matched_tags).where(
            UserFeed.user_id == user_uuid,
            UserFeed.is_dismissed == False
        ).limit(200)
    )

    # 阅读状态分布
    status_result = await db.execute(
        select(UserLiterature.reading_status, func.count(UserLiterature.id))
        .where(UserLiterature.user_id == user_uuid)
        .group_by(UserLiterature.reading_status)
    )
    reading_status_dist = {row[0]: row[1] for row in status_result}
    tag_counter: Counter = Counter()
    for (mt,) in feed_tags:
        for t in (mt or []):
            tid = t.get("tag_id")
            if tid:
                tag_counter[str(tid)] += 1

    # 从 GlobalTag 查询标签中文名称
    tag_name_map: dict[str, str] = {}
    if tag_counter:
        uuids = []
        for tid_str in tag_counter:
            try:
                uuids.append(uuid.UUID(tid_str))
            except ValueError:
                pass
        if uuids:
            result = await db.execute(
                select(GlobalTag.id, GlobalTag.name_zh).where(GlobalTag.id.in_(uuids))
            )
            for row_id, name_zh in result:
                tag_name_map[str(row_id)] = name_zh or str(row_id)[:8]

    top_tags = tag_counter.most_common(15)
    top_tags_list = [{"name": tag_name_map.get(tid, tid[:8]), "count": cnt} for tid, cnt in top_tags]

    return {
        "stats": {"saved": saved, "rated": rated, "notes": notes, "subscriptions": subs,
                   "total_feed": total_feed, "read": read_count, "active_days_7d": active_days,
                   "read_rate": round(read_count / max(1, total_feed) * 100)},
        "top_journals": top_journals,
        "top_tags": top_tags_list,
        "reading_status_dist": reading_status_dist,
    }


@router.get("/profile/weekly-report", summary="阅读周报")
async def weekly_report(db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user)):
    """生成 Markdown 格式的每周阅读报告"""
    from fastapi.responses import PlainTextResponse
    user_uuid = uid(user)

    saved = (await db.execute(select(func.count(UserLiterature.id)).where(UserLiterature.user_id == user_uuid))).scalar() or 0
    notes_count = (await db.execute(select(func.count(UserNote.id)).where(UserNote.user_id == user_uuid))).scalar() or 0
    total_feed = (await db.execute(select(func.count(UserFeed.id)).where(UserFeed.user_id == user_uuid, UserFeed.is_dismissed == False))).scalar() or 0
    read_count = (await db.execute(select(func.count(UserFeed.id)).where(UserFeed.user_id == user_uuid, UserFeed.is_read == True))).scalar() or 0

    from app.models.literature import GlobalLiterature
    j_result = await db.execute(
        select(GlobalLiterature.journal, func.count(GlobalLiterature.id).label("cnt"))
        .join(UserLiterature, UserLiterature.literature_id == GlobalLiterature.id)
        .where(UserLiterature.user_id == user_uuid)
        .group_by(GlobalLiterature.journal).order_by(text("cnt DESC")).limit(5)
    )
    top_journals = [f"{j or 'Unknown'} ({c}篇)" for j, c in j_result]

    week_ago = datetime.now(UTC) - timedelta(days=7)
    week_read = (await db.execute(select(func.count(UserFeed.id)).where(UserFeed.user_id == user_uuid, UserFeed.is_read == True, UserFeed.read_at >= week_ago))).scalar() or 0

    lines = [
        f"# 阅读周报 — {datetime.now(UTC).strftime('%Y-%m-%d')}",
        "",
        "## 📊 本周概览",
        f"- 本周阅读：{week_read} 篇",
        f"- 累计收藏：{saved} 篇",
        f"- 阅读笔记：{notes_count} 条",
        f"- 待读文献：{total_feed - read_count} 篇",
        f"- 阅读进度：{round(read_count / max(1, total_feed) * 100)}%",
        "",
        "## 📰 最常阅读期刊",
    ]
    for j in top_journals:
        lines.append(f"- {j}")
    lines.append("")
    lines.append("---")
    lines.append("*由 OncoLit 自动生成*")

    return PlainTextResponse("\n".join(lines), media_type="text/markdown")


@router.get("/profile/calendar", summary="阅读热力图数据")
async def reading_calendar(db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user)):
    """过去 365 天每日阅读活动"""
    user_uuid = uid(user)
    year_ago = datetime.now(UTC) - timedelta(days=365)
    result = await db.execute(
        select(
            func.date(UserFeed.read_at).label("day"),
            func.count(UserFeed.id).label("cnt"),
        ).where(
            UserFeed.user_id == user_uuid,
            UserFeed.is_read == True,
            UserFeed.read_at >= year_ago,
        ).group_by(text("day")).order_by(text("day"))
    )
    days = [{"date": str(row.day), "count": row.cnt} for row in result]
    return {"days": days}


@router.get("/profile/reading-trend", summary="阅读趋势")
async def reading_trend(days: int = Query(30, ge=7, le=365), db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user)):
    """过去 N 天每日阅读趋势"""
    user_uuid = uid(user)
    since = datetime.now(UTC) - timedelta(days=days)
    result = await db.execute(
        select(
            func.date(UserFeed.read_at).label("day"),
            func.count(UserFeed.id).label("cnt"),
        ).where(
            UserFeed.user_id == user_uuid,
            UserFeed.is_read == True,
            UserFeed.read_at >= since,
        ).group_by(text("day")).order_by(text("day"))
    )
    trend = [{"date": str(row.day), "count": row.cnt} for row in result]
    return {"trend": trend, "days": days}


@router.get("/profile/recent-activity", summary="最近阅读活动")
async def recent_activity(db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user)):
    """最近 10 条阅读记录，含文献信息"""
    from app.models.literature import GlobalLiterature
    user_uuid = uid(user)
    result = await db.execute(
        select(GlobalLiterature.pmid, GlobalLiterature.title, GlobalLiterature.journal,
               GlobalLiterature.pub_date, UserFeed.read_at, UserFeed.priority)
        .join(GlobalLiterature, UserFeed.literature_id == GlobalLiterature.id)
        .where(UserFeed.user_id == user_uuid, UserFeed.is_read == True)
        .order_by(UserFeed.read_at.desc().nullslast())
        .limit(10)
    )
    items = [{
        "pmid": row.pmid,
        "title": row.title[:150] + "…" if len(row.title) > 150 else row.title,
        "journal": row.journal,
        "pub_date": str(row.pub_date) if row.pub_date else None,
        "read_at": row.read_at.isoformat() if row.read_at else None,
        "priority": row.priority,
    } for row in result]
    return {"items": items}


@router.get("/activity-history", summary="浏览历史")
async def activity_history(
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
    activity_type: str = Query(None),
    page: int = Query(1, ge=1),
    page_size: int = Query(30, ge=1, le=100),
    days: int = Query(7, ge=1, le=365),
):
    """当前用户的站内活动历史"""
    user_uuid = uid(user)
    since = datetime.now(UTC) - timedelta(days=days)
    q = select(UserActivityLog).where(
        UserActivityLog.user_id == user_uuid,
        UserActivityLog.created_at >= since,
    )
    count_q = select(func.count(UserActivityLog.id)).where(
        UserActivityLog.user_id == user_uuid,
        UserActivityLog.created_at >= since,
    )
    if activity_type:
        q = q.where(UserActivityLog.activity_type == activity_type)
        count_q = count_q.where(UserActivityLog.activity_type == activity_type)
    total = (await db.execute(count_q)).scalar() or 0
    offset = (page - 1) * page_size
    result = await db.execute(
        q.order_by(UserActivityLog.created_at.desc())
        .offset(offset).limit(page_size)
    )
    items = []
    for row in result.scalars():
        items.append({
            "id": str(row.id),
            "activity_type": row.activity_type,
            "target_type": row.target_type,
            "target_id": row.target_id,
            "detail": row.detail,
            "duration_seconds": row.duration_seconds,
            "ip_address": row.ip_address,
            "session_id": row.session_id,
            "created_at": row.created_at.isoformat() if row.created_at else None,
        })
    return {"items": items, "total": total, "page": page, "page_size": page_size}
