"""Selectors for querying message-related data."""

from __future__ import annotations

import base64
from datetime import datetime
from typing import TypedDict

from messages.models import Thread


class PageInfoDict(TypedDict):
    """Type definition for page info dictionary."""

    has_next_page: bool
    has_previous_page: bool
    start_cursor: str | None
    end_cursor: str | None


class ActivityFeedResult(TypedDict):
    """Type definition for activity feed result."""

    items: list[Thread]
    page_info: PageInfoDict
    total_count: int


def get_activity_feed(
    *,
    workspace_id: str,
    first: int = 20,
    after: str | None = None,
    source_id: str | None = None,
) -> ActivityFeedResult:
    """
    Get paginated activity feed for workspace using existing Thread model.

    Args:
        workspace_id: The workspace to fetch feed for.
        first: Number of items to fetch (default: 20).
        after: Cursor for pagination (base64-encoded timestamp).
        source_id: Optional filter by specific source.

    Returns:
        Dictionary containing items, page_info, and total_count.
    """
    # Build base queryset
    queryset = (
        Thread.objects.filter(workspace_id=workspace_id)
        .select_related("source")
        .order_by("-activity_at", "-created_at")
    )

    # Apply source filter
    if source_id:
        queryset = queryset.filter(source_id=source_id)

    # Get total count before pagination
    total_count = queryset.count()

    # Apply cursor pagination
    if after:
        try:
            cursor_value = base64.b64decode(after).decode()
            # Parse the timestamp
            cursor_dt = datetime.fromisoformat(cursor_value)
            queryset = queryset.filter(activity_at__lt=cursor_dt)
        except (ValueError, UnicodeDecodeError):
            # Invalid cursor, ignore and return from start
            pass

    # Fetch one extra to check if there are more items
    items = list(queryset[: first + 1])
    has_next = len(items) > first
    items = items[:first]

    # Build cursors
    start_cursor: str | None = None
    end_cursor: str | None = None

    if items:
        # Use activity_at if available, fall back to created_at
        first_item_time = items[0].activity_at or items[0].created_at
        last_item_time = items[-1].activity_at or items[-1].created_at

        if first_item_time:
            start_cursor = base64.b64encode(first_item_time.isoformat().encode()).decode()
        if last_item_time:
            end_cursor = base64.b64encode(last_item_time.isoformat().encode()).decode()

    return {
        "items": items,
        "page_info": {
            "has_next_page": has_next,
            "has_previous_page": after is not None,
            "start_cursor": start_cursor,
            "end_cursor": end_cursor,
        },
        "total_count": total_count,
    }
