import type { Hex } from "viem"

/**
 * An attribute as the node renders it: the name, the type **tag** (not the wire typeId), and the
 * value in the JSON encoding that type prescribes — a JSON number for `i32`, a `0x` QUANTITY for
 * `u64` and `u256`, a decimal string for `dec`, `0x` DATA for the byte-shaped types (`bytes`
 * included), and a string for `str`.
 *
 * The encoding follows the *declared type*, never the magnitude, so a decoder dispatches on `type`
 * and never has to guess from the shape of the value.
 */
export type RpcAttribute = {
  name: string
  type: string
  value: unknown
}

/**
 * An entry of the `attributeSchema` projection — a name, its type, and whether the node indexes
 * it, with no value.
 */
export type RpcAttributeSchemaEntry = {
  name: string
  type: string
  indexed?: boolean
}

/**
 * The `creationFlags` projection.
 */
export type RpcCreationFlags = {
  readonly?: boolean
  permissionlessExtension?: boolean
  raw: number
}

/**
 * An entity as `arkiv_query` returns it. Every field is present only if it was selected, so all of
 * them are optional here — {@link RpcSelect} is what decides which arrive.
 */
export type RpcEntity = {
  key?: Hex
  owner?: Hex
  creator?: Hex
  createdAt?: Hex
  updatedAt?: Hex
  expiresAt?: Hex
  creationFlags?: RpcCreationFlags | number
  attributeSchema?: RpcAttributeSchemaEntry[]
  attributes?: RpcAttribute[]
}

/**
 * The `select` projection: flat, per-field booleans. Everything except `key` defaults to **off**,
 * so a query asks for exactly what it needs and nothing more.
 *
 * `attributes` is the one field with a third form: `true` for every attribute, or a map of names
 * for a subset.
 */
export type RpcSelect = {
  key?: boolean
  owner?: boolean
  creator?: boolean
  createdAt?: boolean
  updatedAt?: boolean
  expiresAt?: boolean
  creationFlags?: boolean
  attributeSchema?: boolean
  attributes?: boolean | Record<string, boolean>
  /**
   * Not a field of each entity but of the page: the number of entities the query matches at the
   * block, regardless of `limit` and `offset`, returned as the response's `count`.
   */
  count?: boolean
}

/** The second parameter of `arkiv_query` — what to return, and where in the results to start. */
export type RpcQueryOptions = {
  /** What to return. Defaults to `{ key: true }`. */
  select?: RpcSelect
  /** Page size, as a hex quantity. Node maximum is 100. */
  limit?: Hex
  /** How many matches to skip before the page, as a hex quantity. Defaults to none. */
  offset?: Hex
}

export type ArkivRpcSchema = [
  {
    Method: "arkiv_query"
    Parameters?: [query: string, queryOptions?: RpcQueryOptions]
    ReturnType: {
      data: RpcEntity[]
      blockNumber: Hex
      /** How many entities the query matches, as a hex quantity. Present only when selected. */
      count?: Hex
    }
  },
  {
    Method: "arkiv_getEntity"
    Parameters: [entityKey: Hex]
    /** Every field except `attributeSchema`, or `null` if no live entity has the key. */
    ReturnType: RpcEntity | null
  },
  {
    Method: "arkiv_getBlockTiming"
    Parameters?: []
    ReturnType: {
      current_block: bigint
      current_block_time: number
      duration: number
    }
  },
]
