from typing import List, Literal, Union

from ninja import Field, Schema

from catalog.common.models import Item
from common.api import NOT_FOUND, Result, api
from journal.models.index import JournalIndex, JournalQueryParser


class CustomEmoji(Schema):
    shortcode: str
    url: str
    static_url: str
    visible_in_picker: bool
    category: str


class AccountField(Schema):
    name: str
    value: str
    verified_at: str | None = None


class Account(Schema):
    id: str
    username: str
    acct: str
    url: str
    display_name: str
    note: str
    avatar: str
    avatar_static: str
    header: str
    header_static: str
    locked: bool
    fields: list[AccountField]
    emojis: list[CustomEmoji]
    bot: bool
    group: bool
    discoverable: bool
    indexable: bool
    moved: Union[None, bool, "Account"] = None
    suspended: bool = False
    limited: bool = False
    created_at: str
    # last_status_at: str | None = Field(...)
    # statuses_count: int | None
    # followers_count: int | None
    # following_count: int | None
    # source: dict | None = None


class MediaAttachment(Schema):
    id: str
    type: Literal["unknown", "image", "gifv", "video", "audio"]
    url: str
    preview_url: str
    remote_url: str | None = None
    meta: dict
    description: str | None = None
    blurhash: str | None = None


class StatusMention(Schema):
    id: str
    username: str
    url: str
    acct: str


class StatusTag(Schema):
    name: str
    url: str


class Post(Schema):
    id: str
    uri: str
    created_at: str
    account: Account
    content: str
    visibility: Literal["public", "unlisted", "private", "direct"]
    sensitive: bool
    spoiler_text: str
    media_attachments: list[MediaAttachment]
    mentions: list[StatusMention]
    tags: list[StatusTag]
    emojis: list[CustomEmoji]
    reblogs_count: int
    favourites_count: int
    replies_count: int
    url: str | None = Field(...)
    in_reply_to_id: str | None = Field(...)
    in_reply_to_account_id: str | None = Field(...)
    # reblog: Optional["Status"] = Field(...)
    # poll: Poll | None = Field(...)
    # card: None = Field(...)
    language: str | None = Field(...)
    text: str | None = Field(...)
    edited_at: str | None = None
    favourited: bool = False
    reblogged: bool = False
    muted: bool = False
    bookmarked: bool = False
    pinned: bool = False
    ext_neodb: dict | None = None


class PaginatedPostList(Schema):
    data: List[Post]
    pages: int
    count: int


PostTypes = {"mark", "comment", "review", "collection"}


@api.get(
    "/item/{item_uuid}/posts/",
    response={200: PaginatedPostList, 401: Result, 404: Result},
    tags=["catalog"],
)
def list_posts_for_item(request, item_uuid: str, type: str | None = None):
    """
    Get posts for an item

    `type` is optional, can be a comma separated list of "comment", "review", "collection", "mark"; default is "comment,review"
    """
    item = Item.get_by_url(item_uuid)
    if not item:
        return NOT_FOUND
    types = [t for t in (type or "").split(",") if t in PostTypes]
    q = "type:" + ",".join(types or ["comment", "review"])
    query = JournalQueryParser(q)
    query.filter_by_viewer(request.user.identity)
    query.filter("item_id", item.pk)
    r = JournalIndex.instance().search(query)
    result = {
        "data": [
            p.to_mastodon_json()
            for p in r.posts.prefetch_related("attachments", "author")
        ],
        "pages": r.pages,
        "count": r.total,
    }
    return result
