from __future__ import annotations

from typing import TYPE_CHECKING

from typing_extensions import NotRequired, TypedDict


if TYPE_CHECKING:
    from uuid import UUID


# These are largely generated by https://json2pyi.pages.dev/#TypedDictClass
# These are not guaranteed to be perfect.
#  Sometimes a key is not required but is listed here as required, etc.
#  but this helps a lot with type-checking anyway.


class QueryResponse(TypedDict):
    listings: list[Listing]
    # topBlock: list[Any]  # noqa: ERA001
    facets: list[Facet]
    totalResultCount: int
    maxAllowedPageNumber: int
    correlationId: UUID
    originalQuery: str
    sortOptions: list[SortOption]
    isSearchSaved: bool
    hasErrors: bool
    # alternativeLocales: list[Any]  # noqa: ERA001
    searchRequest: SearchRequestOrOriginalRequest
    searchCategory: int
    searchCategoryOptions: list[SearchCategoryOption]
    # seoFriendlyAttributes: list[Any]  # noqa: ERA001
    # seoFriendlyTextAttributes: SeoFriendlyTextAttributes  # noqa: ERA001
    attributeHierarchy: AttributeHierarchy
    # categoriesById: CategoriesById  # noqa: ERA001
    metaTags: MetaTags


class Listing(TypedDict):
    itemId: str
    title: str
    description: str
    categorySpecificDescription: str
    thinContent: bool
    priceInfo: PriceInfo
    location: Location
    date: str
    imageUrls: list[str]
    sellerInformation: SellerInformation
    categoryId: int
    priorityProduct: str
    videoOnVip: bool
    urgencyFeatureActive: bool
    napAvailable: bool
    attributes: list[Attribute]
    extendedAttributes: list[Attribute]
    traits: list[str]
    verticals: list[str]
    pictures: list[Picture]
    searchType: str
    reserved: bool
    vipUrl: str


class PriceInfo(TypedDict):
    priceCents: int
    priceType: str


class Location(TypedDict):
    cityName: str
    countryName: str
    countryAbbreviation: str
    distanceMeters: int
    isBuyerLocation: bool
    onCountryLevel: bool
    abroad: bool
    latitude: float
    longitude: float


class SellerInformation(TypedDict):
    sellerId: int
    sellerName: str
    showSoiUrl: bool
    showWebsiteUrl: bool
    isVerified: bool


class Attribute(TypedDict):
    key: str
    value: str
    values: list[str]


class Picture(TypedDict):
    id: int
    mediaId: str
    url: str
    extraSmallUrl: str
    mediumUrl: str
    largeUrl: str
    extraExtraLargeUrl: str
    aspectRatio: AspectRatio


class AspectRatio(TypedDict):
    width: int
    height: int


class Facet(TypedDict):
    key: str
    type: str
    categories: NotRequired[list[Category]]
    id: NotRequired[int]
    label: NotRequired[str]
    attributeGroup: NotRequired[list[AttributeGroup]]
    singleSelect: NotRequired[bool]
    categoryId: NotRequired[int]
    range: NotRequired[Range]


class Category(TypedDict):
    id: int
    histogramCount: NotRequired[int]
    selected: bool
    isValuableForSeo: bool
    dominant: bool
    label: str
    key: str
    parentId: int | None
    parentKey: bool | str


class AttributeGroup(TypedDict):
    attributeValueKey: str
    histogramCount: NotRequired[int]
    selected: bool
    isValuableForSeo: bool
    default: NotRequired[bool]
    attributeValueId: NotRequired[int]
    attributeValueLabel: NotRequired[str]


# Cannot use declarative syntax because of keyword
Range = TypedDict("Range", {"from": int, "to": int})


class SortOption(TypedDict):
    sortBy: str
    sortOrder: str


class SearchRequestOrOriginalRequest(TypedDict):
    originalRequest: NotRequired[SearchRequestOrOriginalRequest]
    categories: Categories
    searchQuery: str
    attributes: Attributes
    attributesById: list[int]
    attributesByKey: list[AttributesByKey]
    attributeRanges: list[AttributeRange]
    attributeLabels: list[None]
    sortOptions: SortOptions
    pagination: Pagination
    distance: Distance
    viewOptions: ViewOptions
    bypassSpellingSuggestion: bool


class Categories(TypedDict):
    l1Category: L1Category


class L1Category(TypedDict):
    id: int
    key: str
    fullName: str


class Attributes(TypedDict):
    undefined: list[Undefined]
    offeredSince: list[OfferedSince]


class Undefined(TypedDict):
    attributeValueId: int


class AttributesByKey(TypedDict):
    attributeKey: str
    attributeValueKey: str


# Cannot use declarative syntax because of keyword
AttributeRange = TypedDict(
    "AttributeRange",
    {"attributeKey": str, "from": int, "to": int},
)


class SortOptions(TypedDict):
    sortBy: str
    sortOrder: str
    sortAttribute: str


class Pagination(TypedDict):
    offset: int
    limit: int


class Distance(TypedDict):
    postcode: str
    distanceMeters: int


class ViewOptions(TypedDict):
    kind: str


class SearchCategoryOption(TypedDict):
    fullName: str
    id: int
    key: str
    name: str
    parentId: NotRequired[int]
    parentKey: NotRequired[str]


class AttributeHierarchy(TypedDict):
    condition: list[Condition]
    offeredSince: list[OfferedSince]


class Condition(TypedDict):
    attributeValueId: int
    attributeValueLabel: str
    attributeValueKey: str
    attributeLabel: str


class OfferedSince(TypedDict):
    attributeValueId: None
    attributeValueLabel: None
    attributeValueKey: str
    attributeLabel: str
    isDefault: bool


class MetaTags(TypedDict):
    metaTitle: str
    metaDescription: str
    pageTitleH1: str
