extend type CatalogProduct {
  "The list of tag IDs that have been applied to this product"
  tagIds: [ID]

  "The list of tags that have been applied to this product"
  tags(
    "Return only results that come after this cursor. Use this with `first` to specify the number of results to return."
    after: ConnectionCursor,

    "Return only results that come before this cursor. Use this with `last` to specify the number of results to return."
    before: ConnectionCursor,

    "Return at most this many results. This parameter may be used with either `after` or `offset` parameters."
    first: ConnectionLimitInt,

    "Return at most this many results. This parameter may be used with the `before` parameter."
    last: ConnectionLimitInt,

    "Return only results that come after the Nth result. This parameter may be used with the `first` parameter."
    offset: Int,

    "Return results sorted in this order"
    sortOrder: SortOrder = asc,

    "By default, tags are sorted by ID. Set this to sort by one of the other allowed fields"
    sortBy: TagSortByField = _id
  ): TagConnection
}

extend type Shop {
  "Returns a paged list of tags for this shop"
  tags(
    "If set, the query will return only top-level tags or only non-top-level tags. By default, both types of tags are returned."
    isTopLevel: Boolean,

    "Set to true if you want soft deleted tags to be included in the response"
    shouldIncludeDeleted: Boolean = false,

    "Return only results that come after this cursor. Use this with `first` to specify the number of results to return."
    after: ConnectionCursor,

    "Return only results that come before this cursor. Use this with `last` to specify the number of results to return."
    before: ConnectionCursor,

    "Return at most this many results. This parameter may be used with either `after` or `offset` parameters."
    first: ConnectionLimitInt,

    "Return at most this many results. This parameter may be used with the `before` parameter."
    last: ConnectionLimitInt,

    "Return only results that come after the Nth result. This parameter may be used with the `first` parameter."
    offset: Int,

    "Return results sorted in this order"
    sortOrder: SortOrder = asc,

    "By default, tags are sorted by position. Set this to sort by one of the other allowed fields"
    sortBy: TagSortByField = position
  ): TagConnection
}

extend type Tag {
  "A paged list of tags that have this tag as their parent in the tag hierarchy. Currently only three levels are supported."
  subTags(
    "Return only results that come after this cursor. Use this with `first` to specify the number of results to return."
    after: ConnectionCursor,

    "Return only results that come before this cursor. Use this with `last` to specify the number of results to return."
    before: ConnectionCursor,

    "Return at most this many results. This parameter may be used with either `after` or `offset` parameters."
    first: ConnectionLimitInt,

    "Return at most this many results. This parameter may be used with the `before` parameter."
    last: ConnectionLimitInt,

    "Return only results that come after the Nth result. This parameter may be used with the `first` parameter."
    offset: Int,

    "Return results sorted in this order"
    sortOrder: SortOrder = asc,

    "By default, tags are sorted by position. Set this to sort by one of the other allowed fields"
    sortBy: TagSortByField = position
  ): TagConnection
}

"The fields by which you are allowed to sort any query that returns a `TagConnection`"
enum TagSortByField {
  "Tag ID"
  _id

  "Date and time the tag was created"
  createdAt

  "Tag name"
  name

  "Tag position"
  position

  "Date and time the tag was last updated"
  updatedAt
}


"Range operator for DateTime fields"
input TagDateRange {
  "The start of the date range"
  start: DateTime!

  "The end of the date range"
  end: DateTime!
}

"Operators for filtering on a DateTime field"
input TagDateOperators {
  "The value must be equal to the given value"
  eq: DateTime

  "The value must be greater than the given value"
  before: DateTime

  "The value must be greater than or equal to the given value"
  after: DateTime

  "The value must be between the given values"
  between: ProductDateRange
}

"A connection edge in which each node is a `Tag` object"
type TagEdge implements NodeEdge {
  "The cursor that represents this node in the paginated results"
  cursor: ConnectionCursor!

  "The tag"
  node: Tag
}

"""
Wraps a list of `Tags`, providing pagination cursors and information.

For information about what Relay-compatible connections are and how to use them, see the following articles:
- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections)
- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm)
- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html)
"""
type TagConnection {
  "The list of nodes that match the query, wrapped in an edge to provide a cursor string for each"
  edges: [TagEdge]

  """
  You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has,
  if you know you will not need to paginate the results.
  """
  nodes: [Tag]

  "Information to help a client request the next or previous page"
  pageInfo: PageInfo!

  "The total number of nodes that match your query"
  totalCount: Int!
}

extend type Query {
  "Returns a paged list of tags for a shop. You must include a shopId when querying."
  tags(
    "Filter by created timestamp"
    createdAt: TagDateOperators

    "Filter by updated at timestamp"
    updatedAt: TagDateOperators

    "Only tags associated with this shop will be returned"
    shopId: ID!,

    "If provided, this query will do a regex search using the provided filter data, and return only tags that match"
    filter: String

    "Tags to exclude from results"
    excludedTagIds: [ID]

    "If set, the query will return only top-level tags or only non-top-level tags. By default, both types of tags are returned."
    isTopLevel: Boolean,

    "Set to true if you want soft deleted tags to be included in the response"
    shouldIncludeDeleted: Boolean = false,

    "Set to true if you want to include tags that have isVisible set to false"
    shouldIncludeInvisible: Boolean = false,

    "Return only results that come after this cursor. Use this with `first` to specify the number of results to return."
    after: ConnectionCursor,

    "Return only results that come before this cursor. Use this with `last` to specify the number of results to return."
    before: ConnectionCursor,

    "Return at most this many results. This parameter may be used with either `after` or `offset` parameters."
    first: ConnectionLimitInt,

    "Return at most this many results. This parameter may be used with the `before` parameter."
    last: ConnectionLimitInt,

    "Return only results that come after the Nth result. This parameter may be used with the `first` parameter."
    offset: Int,

    "Return results sorted in this order"
    sortOrder: SortOrder = asc,

    "By default, tags are sorted by position. Set this to sort by one of the other allowed fields"
    sortBy: TagSortByField = position
  ): TagConnection
}
