"""
collections.py
This module defines the Collection types for ActivityPub.
These collections are based on the ActivityStreams vocabulary and ActivityPub protocol.

For more information on Collections in ActivityStreams, see:
https://www.w3.org/TR/activitystreams-core/#collections
"""

from collections.abc import Sequence
from enum import Enum
from typing import ClassVar

from pydantic import Field
from pydantic.config import ConfigDict

from phederation.utils.base import ObjectId

from .objects import APObject


class ValidCollection(str, Enum):
    Outbox = "outbox"
    Inbox = "inbox"
    Following = "following"
    Followers = "followers"
    Shares = "shares"
    Likes = "likes"
    Liked = "liked"
    Objects = "objects"
    NodeInfo = "nodeinfo"
    Blocks = "blocks"
    Keys = "keys"
    Users = "users"
    Collections = "collections"


class APCollection(APObject):
    """
    Represents a Collection in ActivityPub.

    A Collection is an unordered set of Objects or Links.

    Specification: https://www.w3.org/TR/activitystreams-vocabulary/#collection
    Usage: https://www.w3.org/TR/activitypub/#collections
    """

    type: str = Field(default="Collection", description="Indicates a Collection")
    total_items: None | int = Field(default=None, ge=0, description="Total number of items")  # Greater than or equal to 0
    current: "str | ObjectId | APCollectionPage | APOrderedCollectionPage | None" = Field(default=None, description="Current page")
    first: "str | ObjectId | APCollectionPage | APOrderedCollectionPage | None" = Field(default=None, description="First page")
    last: "str | ObjectId | APCollectionPage | APOrderedCollectionPage | None" = Field(default=None, description="Last page")
    items: None | Sequence[str | ObjectId | APObject] = Field(default=None, description="Items in the collection")

    model_config: ClassVar[ConfigDict] = ConfigDict(
        json_schema_extra={
            "examples": [
                {
                    "id": "string",
                    "type": "Collection",
                    "attachment": [],
                    "attributedTo": "string",
                    "content": "string",
                    "context": "string",
                    "name": "string",
                    "endTime": "2025-11-09T21:36:53.227Z",
                    "generator": "string",
                    "icon": "string",
                    "image": "string",
                    "inReplyTo": "string",
                    "location": "string",
                    "preview": "string",
                    "published": "2025-11-09T21:36:53.227Z",
                    "replies": "string",
                    "startTime": "2025-11-09T21:36:53.227Z",
                    "summary": "string",
                    "tag": [],
                    "updated": "2025-11-09T21:36:53.228Z",
                    "url": ["string"],
                    "audience": ["string"],
                    "to": ["string"],
                    "bto": ["string"],
                    "cc": ["string"],
                    "bcc": ["string"],
                    "mediaType": "string",
                    "visibility": "public",
                    "likes": "string",
                    "shares": "string",
                    "totalItems": 0,
                    "current": "string",
                    "first": "string",
                    "last": "string",
                    "items": [],
                }
            ]
        }
    )


class APOrderedCollection(APCollection):
    """
    Represents an OrderedCollection in ActivityPub.

    An OrderedCollection is a Collection where the items are strictly ordered.

    Specification: https://www.w3.org/TR/activitystreams-vocabulary/#orderedcollection
    Usage: https://www.w3.org/TR/activitypub/#ordered-collections
    """

    type: str = Field(default="OrderedCollection", description="Indicates an OrderedCollection")
    ordered_items: None | Sequence[str | ObjectId | APObject] = Field(default=None, description="The ordered items")

    model_config: ClassVar[ConfigDict] = ConfigDict(
        json_schema_extra={
            "examples": [
                {
                    "id": "string",
                    "type": "OrderedCollection",
                    "attachment": [],
                    "attributedTo": "string",
                    "content": "string",
                    "context": "string",
                    "name": "string",
                    "endTime": "2025-11-09T21:36:53.227Z",
                    "generator": "string",
                    "icon": "string",
                    "image": "string",
                    "inReplyTo": "string",
                    "location": "string",
                    "preview": "string",
                    "published": "2025-11-09T21:36:53.227Z",
                    "replies": "string",
                    "startTime": "2025-11-09T21:36:53.227Z",
                    "summary": "string",
                    "tag": [],
                    "updated": "2025-11-09T21:36:53.228Z",
                    "url": ["string"],
                    "audience": ["string"],
                    "to": ["string"],
                    "bto": ["string"],
                    "cc": ["string"],
                    "bcc": ["string"],
                    "mediaType": "string",
                    "visibility": "public",
                    "likes": "string",
                    "shares": "string",
                    "totalItems": 0,
                    "current": "string",
                    "first": "string",
                    "last": "string",
                    "orderedItems": [],
                }
            ]
        }
    )


class APCollectionPage(APCollection):
    """
    Represents a CollectionPage in ActivityPub.

    A CollectionPage represents a single page of a Collection.

    Specification: https://www.w3.org/TR/activitystreams-vocabulary/#collectionpage
    Usage: https://www.w3.org/TR/activitypub/#collection-paging
    """

    type: str = Field(default="CollectionPage", description="Indicates a CollectionPage")
    part_of: "None | str | ObjectId | APCollection" = Field(default=None, description="The parent collection")
    next: "None | str | ObjectId | APCollectionPage" = Field(default=None, description="The next page")
    prev: "None | str | ObjectId | APCollectionPage" = Field(default=None, description="The previous page")


class APOrderedCollectionPage(APCollectionPage, APOrderedCollection):
    """
    Represents an OrderedCollectionPage in ActivityPub.

    An OrderedCollectionPage represents a single page of an OrderedCollection.

    Specification: https://www.w3.org/TR/activitystreams-vocabulary/#orderedcollectionpage
    Usage: https://www.w3.org/TR/activitypub/#ordered-collection-paging
    """

    type: str = Field(default="OrderedCollectionPage", description="Indicates an OrderedCollectionPage")
    start_index: None | int = Field(default=None, ge=0, description="The index of the first item")  # Greater than or equal to 0


class APFollowersCollection(APOrderedCollection):
    """Collection of followers."""

    type: str = Field(default="OrderedCollection", description="Indicates an OrderedCollection")
    name: str | None = Field(default="Followers")


class APFollowingCollection(APOrderedCollection):
    """Collection of following."""

    type: str = Field(default="OrderedCollection", description="Indicates an OrderedCollection")
    name: str | None = Field(default="Following")


class APLikedCollection(APOrderedCollection):
    """Collection of liked objects."""

    type: str = Field(default="OrderedCollection", description="Indicates an OrderedCollection")
    name: str | None = Field(default="Liked")


class APSharedCollection(APOrderedCollection):
    """Collection of shared objects."""

    type: str = Field(default="OrderedCollection", description="Indicates an OrderedCollection")
    name: str | None = Field(default="Shared")


class APUsersCollection(APOrderedCollection):
    """Collection of all users."""

    type: str = Field(default="OrderedCollection", description="Indicates an OrderedCollection")
    name: str | None = Field(default="Users")

    model_config: ClassVar[ConfigDict] = ConfigDict(
        json_schema_extra={
            "examples": [
                {
                    "id": "https://example.org/users",
                    "type": "OrderedCollection",
                    "items": [
                        {
                            "id": "https://example.org/users/exampleuser",
                            "type": "Person",
                            "username": "exampleuser",
                            "domain": "example.org",
                            "inbox": "https://example.org/users/exampleuser/inbox",
                            "outbox": "https://example.org/users/exampleuser/outbox",
                            "following": "https://example.org/users/exampleuser/following",
                            "followers": "https://example.org/users/exampleuser/followers",
                            "autoaccept": "True",
                            "shared_inbox": "https://example.org/inbox",
                            "keyId": "https://example.org/keys/c7d3075a-69c8-47fb-92b0-288898d2f015",
                            "createdAt": "2023-01-19 12:44:48.817540",
                            "updatedAt": "None",
                            "lastFetchedAt": "None",
                        }
                    ],
                    "@context": [
                        "https://www.w3.org/ns/activitystreams",
                        "https://w3id.org/security/v1",
                    ],
                }
            ]
        }
    )
