"""团队邀请 + 共享收藏夹 + 活动流 API"""

import uuid as _uuid
from datetime import datetime, timedelta

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

from app.compat import UTC
from app.core.permissions import TenantRole, get_current_user, require_role
from app.core.tenant_context import tenant_ctx
from app.db import get_db
from app.models.interaction import UserActivityLog, UserFolder, UserLiterature
from app.models.team import Invitation, SharedFolder
from app.models.user import Tenant, User, UserTenant
from app.services.email_service import build_invite_email, send_email

router = APIRouter()


class InviteRequest(BaseModel):
    email: EmailStr
    role: str = "viewer"


class AcceptInviteRequest(BaseModel):
    token: str


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


@router.get("/invitations", summary="邀请列表")
async def list_invitations(db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user)):
    """查看当前租户的邀请列表"""
    tid = tenant_ctx.get()
    if not tid:
        return {"items": []}
    result = await db.execute(
        select(Invitation).where(Invitation.tenant_id == _uuid.UUID(tid))
        .order_by(Invitation.created_at.desc())
    )
    items = result.scalars().all()
    return {"items": [{"id": str(i.id), "email": i.email, "role": i.role, "status": i.status,
                        "expires_at": i.expires_at.isoformat() if i.expires_at else None,
                        "created_at": i.created_at.isoformat() if i.created_at else None}
                      for i in items]}


@router.post("/invitations", summary="创建邀请")
async def create_invitation(
    req: InviteRequest,
    background_tasks: BackgroundTasks,
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
    _: str = Depends(require_role(TenantRole.ADMIN)),
):
    """创建邀请链接（需 Admin 及以上权限）"""
    tid = tenant_ctx.get()
    if not tid:
        return {"status": "skipped", "note": "请先创建或加入团队"}

    token = _uuid.uuid4().hex
    expires = datetime.now(UTC) + timedelta(days=7)
    inv = Invitation(
        id=_uuid.uuid4(), tenant_id=_uuid.UUID(tid), inviter_id=uid(user),
        email=req.email, role=req.role, token=token, status="pending",
        expires_at=expires,
    )
    db.add(inv)
    await db.flush()

    # 异步发送邀请邮件（不阻塞 API 返回）
    inviter_result = await db.execute(select(User).where(User.id == uid(user)))
    inviter = inviter_result.scalar()
    tenant_result = await db.execute(select(Tenant).where(Tenant.id == _uuid.UUID(tid)))
    tenant = tenant_result.scalar()
    inviter_name = inviter.display_name if inviter else "未知用户"
    team_name = tenant.name if tenant else "科室团队"
    invite_link = f"/auth/accept?token={token}"
    html_body = build_invite_email(inviter_name, team_name, invite_link)
    background_tasks.add_task(send_email, req.email, f"{inviter_name} 邀请你加入 {team_name}", html_body)

    await db.commit()
    return {"status": "sent", "token": token, "invite_link": invite_link}


@router.post("/invitations/accept", summary="接受邀请")
async def accept_invitation(
    req: AcceptInviteRequest,
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
):
    """接受邀请加入租户"""
    result = await db.execute(select(Invitation).where(Invitation.token == req.token))
    inv = result.scalar()
    if not inv: raise HTTPException(404, "Invalid invite link")
    if inv.status != "pending": raise HTTPException(400, "Invite already used or expired")
    expires = inv.expires_at.replace(tzinfo=None) if inv.expires_at.tzinfo else inv.expires_at
    if expires < datetime.now(UTC).replace(tzinfo=None): raise HTTPException(400, "Invite expired")

    # 检查是否已在租户中
    from app.models.user import UserTenant
    ex = await db.execute(
        select(UserTenant).where(UserTenant.user_id == uid(user), UserTenant.tenant_id == inv.tenant_id)
    )
    if ex.scalar():
        inv.status = "accepted"
        inv.accepted_at = datetime.now(UTC)
        await db.commit()
        return {"status": "already_member"}

    # 加入租户
    db.add(UserTenant(id=_uuid.uuid4(), user_id=uid(user), tenant_id=inv.tenant_id, role=inv.role))
    inv.status = "accepted"
    inv.accepted_at = datetime.now(UTC)
    await db.commit()
    return {"status": "joined", "tenant_id": str(inv.tenant_id), "role": inv.role}


@router.delete("/invitations/{iid}", summary="撤销邀请")
async def revoke_invitation(
    iid: str,
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
    _: str = Depends(require_role(TenantRole.ADMIN)),
):
    result = await db.execute(select(Invitation).where(Invitation.id == _uuid.UUID(iid)))
    inv = result.scalar()
    if not inv: raise HTTPException(404)
    inv.status = "expired"
    await db.commit()
    return {"status": "revoked"}


@router.get("/members", summary="成员列表")
async def list_members(db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user)):
    """当前租户成员列表"""
    from app.models.user import User, UserTenant
    tid = tenant_ctx.get()
    if not tid:
        return {"members": [], "total": 0}
    result = await db.execute(
        select(UserTenant, User).join(User, UserTenant.user_id == User.id)
        .where(UserTenant.tenant_id == _uuid.UUID(tid))
    )
    members = []
    for ut, u in result:
        members.append({"id": str(u.id), "email": u.email, "display_name": u.display_name,
                         "title": u.title, "role": ut.role, "joined_at": ut.joined_at.isoformat() if ut.joined_at else None})
    return {"members": members, "total": len(members)}


@router.put("/members/{muid}/role", summary="修改角色")
async def update_member_role(
    muid: str, role: str = Query("viewer", pattern="^(viewer|editor|admin)$"),
    db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user),
    _: str = Depends(require_role(TenantRole.ADMIN)),
):
    from app.models.user import UserTenant
    tid = tenant_ctx.get()
    if not tid:
        return {"status": "skipped", "note": "请先创建或加入团队"}
    result = await db.execute(
        select(UserTenant).where(UserTenant.user_id == _uuid.UUID(muid), UserTenant.tenant_id == _uuid.UUID(tid))
    )
    ut = result.scalar()
    if not ut: raise HTTPException(404)
    ut.role = role
    await db.commit()
    return {"status": "updated", "role": role}


@router.delete("/members/{muid}", summary="移除成员")
async def remove_member(
    muid: str, db: AsyncSession = Depends(get_db), user: dict = Depends(get_current_user),
    _: str = Depends(require_role(TenantRole.ADMIN)),
):
    tid = tenant_ctx.get()
    if not tid:
        return {"status": "skipped", "note": "请先创建或加入团队"}
    result = await db.execute(
        select(UserTenant).where(UserTenant.user_id == _uuid.UUID(muid), UserTenant.tenant_id == _uuid.UUID(tid))
    )
    ut = result.scalar()
    if not ut: raise HTTPException(404)
    await db.delete(ut)
    await db.commit()
    return {"status": "removed"}


# ─── 共享收藏夹 ───

class SharedFolderCreate(BaseModel):
    name: str
    description: str | None = None
    color: str = "#1a5276"


@router.get("/shared-folders", summary="共享收藏夹列表")
async def list_shared_folders(
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
):
    """租户下的共享收藏夹列表（含文献数）"""
    tid = tenant_ctx.get()
    if not tid:
        return {"folders": []}
    tid_uuid = _uuid.UUID(tid)

    result = await db.execute(
        select(UserFolder, func.count(UserLiterature.id).label("cnt"))
        .outerjoin(UserLiterature, UserLiterature.folder_id == UserFolder.id)
        .where(UserFolder.tenant_id == tid_uuid, UserFolder.is_shared == True)
        .group_by(UserFolder.id)
        .order_by(UserFolder.sort_order, UserFolder.created_at.desc())
    )
    items = []
    for f, cnt in result:
        items.append({
            "id": str(f.id), "name": f.name, "description": f.description,
            "color": f.color, "article_count": cnt,
            "created_by": str(f.user_id),
            "created_at": f.created_at.isoformat() if f.created_at else None,
        })
    return {"folders": items}


@router.post("/shared-folders", summary="创建共享收藏夹")
async def create_shared_folder(
    req: SharedFolderCreate,
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
    _: str = Depends(require_role(TenantRole.ADMIN)),
):
    tid = tenant_ctx.get()
    if not tid:
        return {"status": "skipped", "note": "请先创建或加入团队"}
    tid_uuid = _uuid.UUID(tid)
    user_uuid = _uuid.UUID(user["sub"])

    folder = UserFolder(
        id=_uuid.uuid4(), user_id=user_uuid, tenant_id=tid_uuid,
        name=req.name, description=req.description, color=req.color,
        is_shared=True,
    )
    db.add(folder)
    await db.flush()

    shared = SharedFolder(
        folder_id=folder.id, target_type="tenant",
        target_id=tid_uuid, permission="view", created_by=user_uuid,
    )
    db.add(shared)
    await db.commit()
    return {"status": "created", "id": str(folder.id)}


@router.delete("/shared-folders/{fid}", summary="删除共享收藏夹")
async def delete_shared_folder(
    fid: str,
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
    _: str = Depends(require_role(TenantRole.ADMIN)),
):
    folder = await db.get(UserFolder, _uuid.UUID(fid))
    if not folder: raise HTTPException(404)
    folder.is_shared = False
    await db.execute(
        SharedFolder.__table__.delete().where(SharedFolder.folder_id == _uuid.UUID(fid))
    )
    await db.commit()
    return {"status": "deleted"}


@router.get("/shared-folders/{fid}/articles", summary="共享收藏夹内的文献")
async def list_shared_folder_articles(
    fid: str,
    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)
    folder_uuid = _uuid.UUID(fid)

    # 验证共享收藏夹属于当前租户
    folder = await db.get(UserFolder, folder_uuid)
    if not folder or folder.tenant_id != tid_uuid or not folder.is_shared:
        raise HTTPException(404, "Shared folder not found")

    # 查询该文件夹下所有团队成员的收藏
    from app.models.interaction import UserLiterature
    from app.models.literature import GlobalLiterature

    team_user_ids = select(UserTenant.user_id).where(UserTenant.tenant_id == tid_uuid)

    total_q = select(func.count(UserLiterature.id)).where(
        UserLiterature.folder_id == folder_uuid,
        UserLiterature.user_id.in_(team_user_ids),
    )
    total = (await db.execute(total_q)).scalar() or 0

    result = await db.execute(
        select(UserLiterature, GlobalLiterature, User.display_name)
        .join(GlobalLiterature, UserLiterature.literature_id == GlobalLiterature.id)
        .join(User, UserLiterature.user_id == User.id)
        .where(
            UserLiterature.folder_id == folder_uuid,
            UserLiterature.user_id.in_(team_user_ids),
        )
        .order_by(UserLiterature.saved_at.desc())
        .offset((page - 1) * page_size)
        .limit(page_size)
    )
    items = []
    lit_ids = []
    for ul, lit, name in result:
        items.append({
            "pmid": lit.pmid, "title": lit.title, "journal": lit.journal,
            "pub_year": lit.pub_year, "authors": lit.authors,
            "saved_by": name, "saved_at": ul.saved_at.isoformat() if ul.saved_at else None,
            "doi": lit.doi,
        })
        lit_ids.append(str(lit.id))

    # 加载标签
    from app.services.tag_loader import load_tags_for_literature
    tag_map = await load_tags_for_literature(db, lit_ids)
    for item in items:
        item["tags"] = tag_map.get(str(lit_ids[items.index(item)]), [])

    return {"items": items, "total": total}


# ─── 团队活动 ───

@router.get("/activity", summary="团队活动流")
async def team_activity(
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
    limit: int = Query(20, ge=1, le=100),
):
    """最近的团队活动（成员加入 + 文献收藏）"""
    tid = tenant_ctx.get()
    if not tid:
        return {"activities": []}
    tid_uuid = _uuid.UUID(tid)

    activities = []

    # 成员加入活动
    recent_members = await db.execute(
        select(UserTenant, User)
        .join(User, UserTenant.user_id == User.id)
        .where(UserTenant.tenant_id == tid_uuid)
        .order_by(UserTenant.joined_at.desc())
        .limit(limit)
    )
    for ut, u in recent_members:
        activities.append({
            "type": "member_joined",
            "user_id": str(u.id), "user_name": u.display_name,
            "detail": f"{u.display_name} 加入科室",
            "created_at": ut.joined_at.isoformat() if ut.joined_at else None,
        })

    # 最近收藏活动
    recent_saves = await db.execute(
        select(UserLiterature, User)
        .join(User, UserLiterature.user_id == User.id)
        .where(
            UserLiterature.user_id.in_(
                select(UserTenant.user_id).where(UserTenant.tenant_id == tid_uuid)
            )
        )
        .order_by(UserLiterature.saved_at.desc())
        .limit(limit)
    )
    for ul, u in recent_saves:
        activities.append({
            "type": "literature_saved",
            "user_id": str(u.id), "user_name": u.display_name,
            "detail": f"{u.display_name} 收藏了一篇文献",
            "created_at": ul.saved_at.isoformat() if ul.saved_at else None,
        })

    # 按时间排序，去重取前 limit 条
    activities.sort(key=lambda a: a.get("created_at", ""), reverse=True)
    return {"activities": activities[:limit]}


@router.get("/reading-rankings", summary="阅读排行")
async def reading_rankings(
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
):
    """科室成员阅读量排行（按收藏数）"""
    tid = tenant_ctx.get()
    if not tid:
        return {"rankings": []}
    tid_uuid = _uuid.UUID(tid)

    result = await db.execute(
        select(User.display_name, User.title, User.id.label("uid"), func.count(UserLiterature.id).label("cnt"))
        .join(UserTenant, User.id == UserTenant.user_id)
        .outerjoin(UserLiterature, UserLiterature.user_id == User.id)
        .where(UserTenant.tenant_id == tid_uuid)
        .group_by(User.id, User.display_name, User.title)
        .order_by(func.count(UserLiterature.id).desc())
    )
    rankings = [
        {"user_id": str(uid), "display_name": name, "title": title, "saved_count": cnt}
        for name, title, uid, cnt in result
    ]
    return {"rankings": rankings}


# ─── 成员审计 ───

@router.get("/member-stats", summary="成员活跃度统计")
async def member_stats(
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
    _: str = Depends(require_role(TenantRole.ADMIN)),
):
    """各成员聚合统计：PV量、行为数、活跃天数、最后活动时间、收藏数（admin/owner only）"""
    tid = tenant_ctx.get()
    if not tid:
        return {"members": []}
    tid_uuid = _uuid.UUID(tid)

    # 租户成员 ID 列表
    member_ids = select(UserTenant.user_id).where(UserTenant.tenant_id == tid_uuid)

    # 活跃天数 + 最后活动时间
    from sqlalchemy import Date as sa_Date, cast as sa_cast
    active_days_q = select(
        UserActivityLog.user_id,
        func.count(func.distinct(sa_cast(UserActivityLog.created_at, sa_Date))).label("active_days"),
        func.max(UserActivityLog.created_at).label("last_active"),
    ).where(
        UserActivityLog.user_id.in_(member_ids),
        UserActivityLog.tenant_id == tid_uuid,
    ).group_by(UserActivityLog.user_id)

    active_days_result = await db.execute(active_days_q)
    active_days_map = {}
    for uid, days, last_active in active_days_result:
        active_days_map[uid] = {"active_days": days, "last_active": last_active.isoformat() if last_active else None}

    # 每人各类活动的计数
    type_count_q = select(
        UserActivityLog.user_id,
        UserActivityLog.activity_type,
        func.count(UserActivityLog.id).label("cnt"),
    ).where(
        UserActivityLog.user_id.in_(member_ids),
        UserActivityLog.tenant_id == tid_uuid,
    ).group_by(UserActivityLog.user_id, UserActivityLog.activity_type)

    type_counts: dict[_uuid.UUID, dict[str, int]] = {}
    for row in (await db.execute(type_count_q)):
        uid, atype, cnt = row
        type_counts.setdefault(uid, {})[atype] = cnt

    # 收藏数
    saved_q = select(
        UserLiterature.user_id,
        func.count(UserLiterature.id).label("saved_cnt"),
    ).where(
        UserLiterature.user_id.in_(member_ids),
    ).group_by(UserLiterature.user_id)
    saved_map: dict[_uuid.UUID, int] = {}
    for uid, cnt in (await db.execute(saved_q)):
        saved_map[uid] = cnt

    # 成员信息
    members_result = await db.execute(
        select(UserTenant, User)
        .join(User, UserTenant.user_id == User.id)
        .where(UserTenant.tenant_id == tid_uuid)
    )
    items = []
    for ut, u in members_result:
        uid = u.id
        ad = active_days_map.get(uid, {})
        tc = type_counts.get(uid, {})
        pv = tc.get("page_view", 0)
        actions = sum(v for k, v in tc.items() if k != "page_view")
        items.append({
            "user_id": str(uid),
            "display_name": u.display_name,
            "email": u.email,
            "title": u.title,
            "role": ut.role,
            "pv_count": pv,
            "action_count": actions,
            "active_days": ad.get("active_days", 0),
            "last_active": ad.get("last_active"),
            "saved_count": saved_map.get(uid, 0),
        })

    return {"items": items}


@router.get("/activity-audit", summary="团队活动审计")
async def activity_audit(
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
    _: str = Depends(require_role(TenantRole.ADMIN)),
    activity_type: str = Query(None),
    user_id: str = Query(None),
    days: int = Query(7, ge=1, le=365),
    page: int = Query(1, ge=1),
    page_size: int = Query(30, ge=1, le=100),
):
    """详细活动日志（含 display_name / ip / user_agent），admin/owner only"""
    tid = tenant_ctx.get()
    if not tid:
        return {"items": [], "total": 0}
    tid_uuid = _uuid.UUID(tid)
    since = datetime.now(UTC) - timedelta(days=days)

    member_ids = select(UserTenant.user_id).where(UserTenant.tenant_id == tid_uuid)

    q = select(UserActivityLog, User.display_name).join(
        User, UserActivityLog.user_id == User.id
    ).where(
        UserActivityLog.user_id.in_(member_ids),
        UserActivityLog.tenant_id == tid_uuid,
        UserActivityLog.created_at >= since,
    )
    count_q = select(func.count(UserActivityLog.id)).where(
        UserActivityLog.user_id.in_(member_ids),
        UserActivityLog.tenant_id == tid_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)
    if user_id:
        q = q.where(UserActivityLog.user_id == _uuid.UUID(user_id))
        count_q = count_q.where(UserActivityLog.user_id == _uuid.UUID(user_id))

    total = (await db.execute(count_q)).scalar() or 0
    result = await db.execute(
        q.order_by(UserActivityLog.created_at.desc())
        .offset((page - 1) * page_size)
        .limit(page_size)
    )

    items = []
    for row in result:
        log, display_name = row
        items.append({
            "id": str(log.id),
            "user_id": str(log.user_id) if log.user_id else None,
            "display_name": display_name,
            "activity_type": log.activity_type,
            "target_type": log.target_type,
            "target_id": log.target_id,
            "detail": log.detail,
            "ip_address": log.ip_address,
            "user_agent": log.user_agent,
            "duration_seconds": log.duration_seconds,
            "created_at": log.created_at.isoformat() if log.created_at else None,
        })

    return {"items": items, "total": total, "page": page, "page_size": page_size}
