"""This directive allows results to be deferred during execution"""
directive @defer on FIELD

"""
Tells the service this field/object has access authorized by sigv4 signing.
"""
directive @aws_iam on OBJECT | FIELD_DEFINITION

"""
Tells the service this field/object has access authorized by an API key.
"""
directive @aws_api_key on OBJECT | FIELD_DEFINITION

"""
Tells the service this field/object has access authorized by a Lambda Authorizer.
"""
directive @aws_lambda on OBJECT | FIELD_DEFINITION

"""Directs the schema to enforce authorization on a field"""
directive @aws_auth(
  """List of cognito user pool groups which have access on this field"""
  cognito_groups: [String]
) on FIELD_DEFINITION

"""Tells the service which mutation triggers this subscription."""
directive @aws_subscribe(
  """
  List of mutations which will trigger this subscription when they are called.
  """
  mutations: [String]
) on FIELD_DEFINITION

"""
Tells the service which subscriptions will be published to when this mutation is
called. This directive is deprecated use @aws_susbscribe directive instead.
"""
directive @aws_publish(
  """
  List of subscriptions which will be published to when this mutation is called.
  """
  subscriptions: [String]
) on FIELD_DEFINITION

"""
Tells the service this field/object has access authorized by a Cognito User Pools token.
"""
directive @aws_cognito_user_pools(
  """List of cognito user pool groups which have access on this field"""
  cognito_groups: [String]
) on OBJECT | FIELD_DEFINITION

"""
Tells the service this field/object has access authorized by an OIDC token.
"""
directive @aws_oidc on OBJECT | FIELD_DEFINITION

enum ActivityType {
  APPROVE
  CANCEL
  CLAIM
  SEND
  RECEIVE
  SWAP
  DEPLOYMENT
  UNKNOWN
  money
  market
  LEND
  BORROW
  REPAY
  WITHDRAW
  NFT
  MINT
  BURN
  Staking
  STAKE
  UNSTAKE
}

type Amount implements IAmount {
  id: ID!
  currency: Currency
  value: Float
}

type AssetActivity {
  id: ID!
  timestamp: Int!
  type: ActivityType!
  gasUsed: Float
  transaction: Transaction!
  assetChanges: [AssetChange]!
}

union AssetChange = TokenTransfer | NftTransfer | TokenApproval | NftApproval | NftApproveForAll

enum Chain {
  ARBITRUM
  ETHEREUM
  ETHEREUM_GOERLI
  OPTIMISM
  POLYGON
  CELO
}

input ContractInput {
  chain: Chain!
  address: String
}

enum Currency {
  USD
  ETH
}

type Dimensions {
  id: ID!
  height: Float
  width: Float
}

enum HighLow {
  HIGH
  LOW
}

enum HistoryDuration {
  HOUR
  DAY
  WEEK
  MONTH
  YEAR
  MAX
}

interface IAmount {
  currency: Currency
  value: Float
}

interface IContract {
  chain: Chain!
  address: String
}

type Image {
  id: ID!
  url: String
  dimensions: Dimensions
}

enum MarketSortableField {
  MARKET_CAP
  VOLUME
}

type NftApproval {
  id: ID!
  nftStandard: NftStandard!

  """  can be erc20 or erc1155"""
  asset: NftAsset!
  approvedAddress: String!
}

type NftApproveForAll {
  id: ID!
  nftStandard: NftStandard!

  """  can be erc721 or erc1155"""
  asset: NftAsset!
  operatorAddress: String!
  approved: Boolean!
}

type NftAsset {
  id: ID!
  collection: NftCollection
  description: String
  imageUrl: String
  thumbnailUrl: String
  animationUrl: String
  smallImageUrl: String
  image: Image
  thumbnail: Image
  smallImage: Image
  name: String
  nftContract: NftContract

  """
    TODO: may need to be array to support erc1155 cases. not needed at the moment so will revisit.
   ownerAddress: String
  """
  tokenId: String
  traits: [NftAssetTrait]
}

enum NftAssetSortableField {
  PRICE
}

type NftAssetTrait {
  id: ID!
  name: String
  rarity: Float
  value: String
}

type NftBalance {
  id: ID!
  ownedAsset: NftAsset
}

type NftCollection {
  id: ID!
  collectionId: String

  """
    TODO: support querying for collection assets here
   assets(page: Int, pageSize: Int, orderBy: NftAssetSortableField): [NftAsset]
  """
  bannerImageUrl: String
  bannerImage: Image
  description: String
  discordUrl: String
  homepageUrl: String
  imageUrl: String
  image: Image
  instagramName: String
  markets(currencies: [Currency!]!): [NftCollectionMarket]
  name: String
  nftContracts: [NftContract]
  openseaUrl: String

  """
    TODO: support collection-level traits.
   traits: [NftCollectionTraits] (not needed yet)
  """
  twitterName: String
  isVerified: Boolean
  numAssets: Int
}

type NftCollectionMarket {
  id: ID!
  floorPrice: Amount
  owners: Int
  volume24h: Amount
  totalVolume: Amount
}

type NftCollectionTraits {
  id: ID!
  name: String
  values: [String]
}

type NftContract implements IContract {
  id: ID!
  address: String
  chain: Chain!
  name: String
  standard: NftStandard
  symbol: String
  totalSupply: Int
}

enum NftMarketSortableField {
  VOLUME
  FLOOR_PRICE
}

enum NftStandard {
  ERC721
  ERC1155
  NONCOMPLIANT
}

type NftTransfer {
  id: ID!
  nftStandard: NftStandard!
  asset: NftAsset!
  sender: String!
  recipient: String!
  direction: TransactionDirection!
}

type Portfolio {
  id: ID!
  ownerAddress: String!
  tokensTotalDenominatedValue: Amount
  tokensTotalDenominatedValueHistory(duration: HistoryDuration): [TimestampedAmount]
  tokenBalances: [TokenBalance]
  assetsValueUSD: Float
  totalValueUSD: Float
  assetsValue: Float
  totalValue: Float
  absoluteChange24H: Float
  relativeChange24H: Float
  nftBalances: [NftBalance]
}

type Query {
  tokens(contracts: [ContractInput!]!): [Token]
  tokenProjects(contracts: [ContractInput!]!): [TokenProject]
  topTokenProjects(orderBy: MarketSortableField!, page: Int!, pageSize: Int!, currency: Currency): [TokenProject]
  searchTokens(searchQuery: String!): [Token]
  searchTokenProjects(searchQuery: String!): [TokenProject]
  assetActivities(address: String!, page: Int, pageSize: Int): [AssetActivity]
  portfolio(ownerAddress: String!): Portfolio
  portfolios(ownerAddresses: [String!]!): [Portfolio]
  nftCollectionsById(collectionIds: [String]): [NftCollection]
  topTokens(chain: Chain, page: Int!, pageSize: Int!): [Token]
}

type TimestampedAmount implements IAmount {
  id: ID!
  currency: Currency
  value: Float
  timestamp: Int!
}

type Token implements IContract {
  id: ID!
  chain: Chain!
  address: String
  standard: TokenStandard
  decimals: Int
  name: String
  symbol: String
  project: TokenProject
  market(currency: Currency): TokenMarket
}

type TokenApproval {
  id: ID!
  tokenStandard: TokenStandard!

  """  can be erc20 or erc1155"""
  asset: Token!
  approvedAddress: String!
  quantity: String!
}

type TokenBalance {
  id: ID!
  blockNumber: Int
  blockTimestamp: Int
  quantity: Float
  denominatedValue: Amount
  ownerAddress: String!
  token: Token
  tokenProjectMarket: TokenProjectMarket
}

type TokenMarket {
  id: ID!
  token: Token!
  price: Amount
  totalValueLocked: Amount
  volume(duration: HistoryDuration!): Amount
  pricePercentChange(duration: HistoryDuration!): Amount
  priceHistory(duration: HistoryDuration!): [TimestampedAmount]
}

type TokenProject {
  id: ID!
  name: String
  tokens: [Token!]!
  description: String
  twitterName: String
  homepageUrl: String
  logoUrl: String
  markets(currencies: [Currency!]!): [TokenProjectMarket]
}

type TokenProjectMarket {
  id: ID!
  tokenProject: TokenProject!
  currency: Currency!
  price: Amount
  volume24h: Amount
  pricePercentChange24h: Amount
  marketCap: Amount
  fullyDilutedMarketCap: Amount
  priceHistory(duration: HistoryDuration!): [TimestampedAmount]
  volume(duration: HistoryDuration!): Amount
  pricePercentChange(duration: HistoryDuration!): Amount
  priceHighLow(duration: HistoryDuration!, highLow: HighLow!): Amount
}

enum TokenStandard {
  NATIVE
  ERC20
  ERC1155
}

type TokenTransfer {
  id: ID!
  tokenStandard: TokenStandard!
  asset: Token!
  sender: String!
  recipient: String!
  quantity: String!
  direction: TransactionDirection!
  transactedValue: Amount
}

type Transaction {
  id: ID!
  blockNumber: Int!
  from: String!
  to: String!
  hash: String!
  nonce: Int!
  gasLimit: Float
  maxFeePerGas: Float
  status: TransactionStatus!
}

enum TransactionDirection {
  IN
  OUT
  SELF
}

enum TransactionStatus {
  FAILED
  CONFIRMED
  PENDING
}

