// TODO: These types should be moved to core, and probably inferred by io-ts
export interface RpcBlockOutput {
  difficulty: string;
  extraData: string;
  gasLimit: string;
  gasUsed: string;
  hash: string | null;
  logsBloom: string;
  miner: string;
  mixHash: string | null;
  nonce: string | null;
  number: string | null;
  parentHash: string;
  receiptsRoot: string;
  sha3Uncles: string;
  size: string;
  stateRoot: string;
  timestamp: string;
  totalDifficulty: string;
  transactions: string[] | RpcTransactionOutput[];
  transactionsRoot: string;
  uncles: string[];
  baseFeePerGas?: string;
  withdrawals?: RpcWithdrawalItem[];
  withdrawalsRoot?: string;
  parentBeaconBlockRoot?: string | null;
  blobGasUsed?: string | null;
  excessBlobGas?: string | null;
}

export type RpcTransactionOutput =
  | LegacyRpcTransactionOutput
  | AccessListEIP2930RpcTransactionOutput
  | EIP1559RpcTransactionOutput;

interface BaseRpcTransactionOutput {
  blockHash: string | null;
  blockNumber: string | null;
  from: string;
  gas: string;
  hash: string;
  input: string;
  nonce: string;
  r: string; // This is documented as DATA, but implementations use QUANTITY
  s: string; // This is documented as DATA, but implementations use QUANTITY
  to: string | null;
  transactionIndex: string | null;
  v: string;
  value: string;
  // Only shown if the local hardfork is at least Berlin, or if the (remote) tx has an access list
  type?: string;
}

export interface LegacyRpcTransactionOutput extends BaseRpcTransactionOutput {
  gasPrice: string;
}

export type RpcAccessListOutput = Array<{
  address: string;
  storageKeys: string[];
}>;

export interface AccessListEIP2930RpcTransactionOutput
  extends BaseRpcTransactionOutput {
  gasPrice: string;
  accessList?: RpcAccessListOutput;
  chainId: string;
}

export interface EIP1559RpcTransactionOutput extends BaseRpcTransactionOutput {
  gasPrice: string;
  maxFeePerGas: string;
  maxPriorityFeePerGas: string;
  accessList?: RpcAccessListOutput;
  chainId: string;
}

export interface RpcReceiptOutput {
  blockHash: string;
  blockNumber: string;
  contractAddress: string | null;
  cumulativeGasUsed: string;
  from: string;
  gasUsed: string;
  logs: RpcLogOutput[];
  logsBloom: string;
  to: string | null;
  transactionHash: string;
  transactionIndex: string;

  // Only present after Byzantium
  status?: string;

  // Only present before Byzantium
  root?: string;

  // Only shown if the local hardfork is at least Berlin, or if the (remote) is not a legacy one
  type?: string;

  // Only shown if the local hardfork is at least London, or if the (remote) is EIP-1559
  effectiveGasPrice?: string;
}

export interface RpcLogOutput {
  address: string;
  blockHash: string | null;
  blockNumber: string | null;
  data: string;
  logIndex: string | null;
  removed: boolean;
  topics: string[];
  transactionHash: string | null;
  transactionIndex: string | null;
}

export interface RpcStructLog {
  depth: number;
  gas: number;
  gasCost: number;
  op: string;
  pc: number;
  memory?: string[];
  stack?: string[];
  storage?: Record<string, string>;
  memSize?: number;
  error?: object;
}

export interface RpcDebugTraceOutput {
  failed: boolean;
  gas: number;
  returnValue: string;
  structLogs: RpcStructLog[];
}

export interface RpcWithdrawalItem {
  index: string;
  validatorIndex: string;
  address: string;
  amount: string;
}
