"""期刊：详情 + 关注 + 文章列表"""
import uuid
from datetime import datetime, date
from collections import Counter

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

from app.compat import UTC
from app.core.permissions import get_current_user
from app.db import get_db
from app.models.interaction import UserJournalSubscription, UserLiterature, UserFeed
from app.models.literature import GlobalJournal, GlobalLiterature
from app.schemas.literature import LiteratureCard, cap_pub_date
from app.services.tag_loader import load_tags_for_literature

router = APIRouter()


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


@router.get("/{issn}", summary="期刊详情")
async def journal_detail(
    issn: str,
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
):
    """期刊元数据 + 用户关注状态 + 我的统计数据"""
    j = (await db.execute(
        select(GlobalJournal).where(GlobalJournal.issn == issn)
    )).scalar()
    if not j:
        # fallback: 按名称匹配
        j = (await db.execute(
            select(GlobalJournal).where(GlobalJournal.name.ilike(f"%{issn}%"))
        )).scalar()
    if not j:
        raise HTTPException(404, detail="期刊未找到")

    user_uuid = uid(user)

    # 关注状态
    sub = (await db.execute(
        select(UserJournalSubscription).where(
            UserJournalSubscription.user_id == user_uuid,
            UserJournalSubscription.journal_id == j.id,
            UserJournalSubscription.is_active == True,
        )
    )).scalar()
    is_following = sub is not None

    # 我的收藏数
    my_saved = (await db.execute(
        select(func.count(UserLiterature.id))
        .join(GlobalLiterature, UserLiterature.literature_id == GlobalLiterature.id)
        .where(
            UserLiterature.user_id == user_uuid,
            func.coalesce(GlobalLiterature.journal_issn, '') == (j.issn or ''),
        )
    )).scalar() or 0

    # 我的已读数
    my_read = (await db.execute(
        select(func.count(UserFeed.id))
        .join(GlobalLiterature, UserFeed.literature_id == GlobalLiterature.id)
        .where(
            UserFeed.user_id == user_uuid,
            UserFeed.is_read == True,
            func.coalesce(GlobalLiterature.journal_issn, '') == (j.issn or ''),
        )
    )).scalar() or 0

    # 年发文趋势（按 pub_year 聚合）
    trend_result = await db.execute(
        select(
            GlobalLiterature.pub_year,
            func.count(GlobalLiterature.id).label("cnt"),
        ).where(
            func.coalesce(GlobalLiterature.journal_issn, '') == (j.issn or ''),
            GlobalLiterature.pub_year.isnot(None),
        ).group_by(GlobalLiterature.pub_year).order_by(GlobalLiterature.pub_year.desc())
        .limit(15)
    )
    yearly_trend = [
        {"year": row.pub_year, "count": row.cnt}
        for row in trend_result
    ]

    return {
        "id": str(j.id),
        "name": j.name,
        "issn": j.issn,
        "eissn": j.eissn,
        "tier": j.tier,
        "impact_factor": j.impact_factor,
        "publisher": j.publisher,
        "article_count": j.article_count,
        "is_active": j.is_active,
        "is_following": is_following,
        "my_saved": my_saved,
        "my_read": my_read,
        "yearly_trend": yearly_trend,
    }


@router.post("/{issn}/follow", summary="关注期刊")
async def follow_journal(
    issn: str,
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
):
    """关注后该期刊的新文献会推送到 Feed"""
    j = (await db.execute(
        select(GlobalJournal).where(GlobalJournal.issn == issn)
    )).scalar()
    if not j:
        raise HTTPException(404, detail="期刊未找到")

    user_uuid = uid(user)

    # 获取 tenant_id
    from app.core.tenant_context import tenant_ctx
    tid = tenant_ctx.get() or uuid.UUID(user.get("tid", ""))

    # upsert
    existing = (await db.execute(
        select(UserJournalSubscription).where(
            UserJournalSubscription.user_id == user_uuid,
            UserJournalSubscription.journal_id == j.id,
        )
    )).scalar()

    if existing:
        if not existing.is_active:
            existing.is_active = True
            await db.commit()
        return {"status": "already_following"}
    else:
        sub = UserJournalSubscription(
            user_id=user_uuid, tenant_id=tid, journal_id=j.id, is_active=True,
        )
        db.add(sub)
        await db.commit()
        return {"status": "following"}


@router.delete("/{issn}/follow", summary="取消关注期刊")
async def unfollow_journal(
    issn: str,
    db: AsyncSession = Depends(get_db),
    user: dict = Depends(get_current_user),
):
    j = (await db.execute(
        select(GlobalJournal).where(GlobalJournal.issn == issn)
    )).scalar()
    if not j:
        raise HTTPException(404, detail="期刊未找到")

    user_uuid = uid(user)
    existing = (await db.execute(
        select(UserJournalSubscription).where(
            UserJournalSubscription.user_id == user_uuid,
            UserJournalSubscription.journal_id == j.id,
            UserJournalSubscription.is_active == True,
        )
    )).scalar()

    if existing:
        existing.is_active = False
        await db.commit()
        return {"status": "unfollowed"}
    return {"status": "not_following"}


@router.get("/{issn}/articles", summary="期刊文章列表")
async def journal_articles(
    issn: 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),
    year: int | None = Query(None, ge=1900, le=2100),
):
    """某期刊下的文章列表，支持按年份筛选"""
    offset = (page - 1) * page_size

    where = [func.coalesce(GlobalLiterature.journal_issn, '') == (issn or '')]
    if year:
        where.append(GlobalLiterature.pub_year == year)

    total = (await db.execute(
        select(func.count(GlobalLiterature.id)).where(*where)
    )).scalar() or 0

    result = await db.execute(
        select(GlobalLiterature).where(*where)
        .order_by(GlobalLiterature.pub_date.desc().nullslast())
        .offset(offset).limit(page_size)
    )
    items = result.scalars().all()

    ids = [str(lit.id) for lit in items]
    tm = await load_tags_for_literature(db, ids)

    # 加载规范期刊名
    jname_map = {}
    jissns = list(set(lit.journal_issn for lit in items if lit.journal_issn))
    if jissns:
        jr = await db.execute(
            select(GlobalJournal.issn, GlobalJournal.name).where(GlobalJournal.issn.in_(jissns))
        )
        for issn_, name_ in jr.all():
            jname_map[issn_] = name_

    # Build cards (minimal)
    user_uuid = uuid.UUID(user["sub"])
    saved_pmids = set()
    if items:
        lit_ids = [lit.id for lit in items]
        saved_rows = await db.execute(
            select(UserLiterature.literature_id, GlobalLiterature.pmid)
            .join(GlobalLiterature, UserLiterature.literature_id == GlobalLiterature.id)
            .where(
                UserLiterature.user_id == user_uuid,
                UserLiterature.literature_id.in_(lit_ids),
            )
        )
        saved_pmids = {row.pmid for row in saved_rows}

    from app.schemas.literature import PublicLiteratureCard

    cards = []
    for lit in items:
        authors = lit.authors or []
        first_author = authors[0].get("family", "") if authors else ""
        tlist = tm.get(str(lit.id), []) if tm else []
        enriched_tags = []
        for t in tlist:
            tag = dict(t)
            if '::' in tag.get('path', ''):
                tag['name_zh'] = tag['path'].split('::')[-1]
            enriched_tags.append(tag)
        journal = jname_map.get(lit.journal_issn) or lit.journal
        cards.append(PublicLiteratureCard(
            id=str(lit.id), pmid=lit.pmid, title=lit.title,
            first_author=first_author, journal=journal,
            pub_date=cap_pub_date(lit.pub_date),
            article_date=lit.article_date.isoformat() if lit.article_date else None,
            doi=lit.doi, pmc_id=lit.pmc_id, is_oa=lit.is_oa,
            cited_by_count=lit.cited_by_count or 0,
            pub_types=lit.pub_types or [],
            tags=enriched_tags,
            retracted=lit.retracted,
            is_negative_result=lit.is_negative_result,
            created_at=lit.created_at.isoformat() if lit.created_at else None,
            updated_at=lit.updated_at.isoformat() if lit.updated_at else None,
        ))

    # 可用年份筛选
    years_result = await db.execute(
        select(GlobalLiterature.pub_year)
        .where(
            func.coalesce(GlobalLiterature.journal_issn, '') == (issn or ''),
            GlobalLiterature.pub_year.isnot(None),
        )
        .distinct().order_by(GlobalLiterature.pub_year.desc())
    )
    available_years = [row[0] for row in years_result]

    return {
        "items": cards,
        "total": total,
        "page": page,
        "page_size": page_size,
        "available_years": available_years,
        "is_saved": list(saved_pmids),
    }
