"""
This module contains models for miscellaneous objects.
"""
from __future__ import annotations

from datetime import datetime
from functools import partial
from typing import Any
from typing import Coroutine
from typing import Literal
from typing import Optional

from emojiflags.lookup import lookup as flag_lookup  # type: ignore
from pydantic import Field
from pydantic import validator

from .base import BaseModel
from .gamemode import Gamemode

__all__ = (
    "Achievement",
    "Country",
    "CurrentUserAttributes",
    "TimestampedCount",
    "CursorModel",
    "SortTypes",
    "HTMLBody",
)


SortTypes = Literal["id_asc", "id_desc"]


class TimestampedCount(BaseModel):
    start_date: datetime
    count: int

    @validator("start_date", pre=True)
    def _date_validate(cls, v: str) -> datetime:
        return datetime.strptime(v, "%Y-%m-%d")


class Achievement(BaseModel):
    id: int
    name: str
    slug: str
    desciption: str
    grouping: str
    icon_url: str
    mode: Gamemode
    ordering: int
    instructions: Optional[str]


class Country(BaseModel):
    code: str
    name: str

    @property
    def flag_emoji(self) -> str:
        r"""Emoji for the flag.

        :return: Unicode emoji representation of the country's flag
        :rtype: str
        """
        return flag_lookup(self.code)


class HTMLBody(BaseModel):
    html: str
    raw: Optional[str]
    bbcode: Optional[str]


class PinAttributes(BaseModel):
    is_pinned: bool
    score_id: int
    score_type: str


class CurrentUserAttributes(BaseModel):
    can_destroy: Optional[bool]
    can_reopen: Optional[bool]
    can_moderate_kudosu: Optional[bool]
    can_resolve: Optional[bool]
    vote_score: Optional[int]
    can_message: Optional[bool]
    can_message_error: Optional[str]
    last_read_id: Optional[int]
    can_new_comment: Optional[bool]
    can_new_comment_reason: Optional[str]
    pin: Optional[PinAttributes]


class CursorModel(BaseModel):
    r"""NOTE: This model is not serializable by orjson directly.

    Use the provided .json() or .dict() methods instead.
    """

    cursor_string: Optional[str]
    next: Optional[partial[Coroutine[Any, Any, CursorModel]]] = Field(exclude=True)
    """Partial function to get the next page of results."""
