from __future__ import annotations

from datetime import datetime

from sqlalchemy.ext.asyncio import AsyncSession

from app.services.publication_identifiers import application as identifier_service
from app.services.publications.modes import (
    MODE_ALL,
    MODE_UNREAD,
    resolve_publication_view_mode,
)
from app.services.publications.queries import (
    get_latest_run_id_for_user,
    get_publication_item_for_user,
    publication_list_item_from_row,
    publications_query,
    unread_item_from_row,
)
from app.services.publications.types import PublicationListItem, UnreadPublicationItem


async def list_for_user(
    db_session: AsyncSession,
    *,
    user_id: int,
    mode: str = MODE_ALL,
    scholar_profile_id: int | None = None,
    favorite_only: bool = False,
    search: str | None = None,
    sort_by: str = "first_seen",
    sort_dir: str = "desc",
    limit: int = 100,
    offset: int = 0,
    snapshot_before: datetime | None = None,
) -> list[PublicationListItem]:
    resolved_mode = resolve_publication_view_mode(mode)
    latest_run_id = await get_latest_run_id_for_user(db_session, user_id=user_id)
    result = await db_session.execute(
        publications_query(
            user_id=user_id,
            mode=resolved_mode,
            latest_run_id=latest_run_id,
            scholar_profile_id=scholar_profile_id,
            favorite_only=favorite_only,
            search=search,
            sort_by=sort_by,
            sort_dir=sort_dir,
            limit=limit,
            offset=offset,
            snapshot_before=snapshot_before,
        )
    )
    rows = [publication_list_item_from_row(row, latest_run_id=latest_run_id) for row in result.all()]
    return await identifier_service.overlay_publication_items_with_display_identifiers(
        db_session,
        items=rows,
    )


async def retry_pdf_for_user(
    db_session: AsyncSession,
    *,
    user_id: int,
    scholar_profile_id: int,
    publication_id: int,
) -> PublicationListItem | None:
    item = await get_publication_item_for_user(
        db_session,
        user_id=user_id,
        scholar_profile_id=scholar_profile_id,
        publication_id=publication_id,
    )
    if item is None:
        return None
    hydrated = await identifier_service.overlay_publication_items_with_display_identifiers(
        db_session,
        items=[item],
    )
    return hydrated[0] if hydrated else item


async def list_unread_for_user(
    db_session: AsyncSession,
    *,
    user_id: int,
    limit: int = 100,
) -> list[UnreadPublicationItem]:
    result = await db_session.execute(
        publications_query(
            user_id=user_id,
            mode=MODE_UNREAD,
            latest_run_id=None,
            scholar_profile_id=None,
            favorite_only=False,
            limit=limit,
            offset=0,
        )
    )
    return [unread_item_from_row(row) for row in result.all()]
