import { Noir } from '@noir-lang/noir_js';
import { Fr, Barretenberg } from '@aztec/bb.js';
import { BarretenbergBackend } from '@noir-lang/backend_barretenberg';
import { CompiledCircuit, ProofData } from '@noir-lang/types';
import { UTXO_Spendable, UTXO_New, ContractOnlyInputs, PublicInputs, Field, MerkleProof } from '../circuits/helpers/codegen/create_transaction';
import { HistoricTreeInput, Verifier, VerifierTx } from '../circuits/helpers/codegen/publish_batch';
import { ethers } from "ethers"
import { Momiji, UltraVerifier, XFTMock, IUniswapV3Pool } from './typechain-types';
import { TransactionStruct, BatchStruct } from './typechain-types/contracts/state.sol/IMomiji';
import { MerkleTree } from '../utils/MerkleTree';
import { BackendOptions } from '@noir-lang/backend_barretenberg';
import { txVk } from "./transaction_circuits"

export type ContractBatch = BatchStruct
export type BatchPublishResponse = ethers.ContractTransactionResponse
export type BatchPublishReceipt = ethers.ContractTransactionReceipt
export type EthersSigner = ethers.Signer
export type EthersEventLog = ethers.EventLog
export type EthersEventResult = ethers.Result
export type UTXO_Spendable_Struct = UTXO_Spendable
export type Merkle_Proof_Struct = MerkleProof
export type UniswapV3Pool = IUniswapV3Pool
export type Provider = ethers.Provider
export type TransactionRequest = ethers.TransactionRequest
export type TypedDataDomain = ethers.TypedDataDomain
export type AddressLike = ethers.AddressLike
export type FeeData = ethers.FeeData
export type ContractTransaction = TransactionStruct
export type PublicCircuitInputs = PublicInputs
export const NoirFr = Fr
export type _NoirFr = Fr
export const BarretenbergApi = Barretenberg
export type _Barretenberg = Barretenberg
export type NoirBackendOptions = BackendOptions

export type slot0 = {
  sqrtPriceX96: bigint;
  tick: bigint;
  observationIndex: bigint;
  observationCardinality: bigint;
  observationCardinalityNext: bigint;
  feeProtocol: bigint;
  unlocked: boolean;
}

export const ZERO_VALUE = "0x016a430aa58685aba1311244a973a3bc358859da86784be51094368e8fb6f720"; // sha256("Momiji") % Fr.MODULUS
export const ZERO_HEX = toFixedHex(0, true)
export const treeConfig = {
  utxoDepth: 4,
  txDepth: 4,
  stateDepth: 20
}

export const default_historic_path: Field[] = [
  "0x016a430aa58685aba1311244a973a3bc358859da86784be51094368e8fb6f720",
  "0x018d39625c19fa2cfbebdb940a66d7040bb0ef1b59ff6afd92a13a6b9b2d9865",
  "0x096c00ebc0c52478316b6b9fd16d0cd94c5f45bbe45bbfa8c606197c6119d41f",
  "0x2eaefd3bdd1bfbddd8fc5d972ded58617f752b3e88bd17b791e85e7b8eaacb47",
  "0x11d25ff6aa8a431fbce8e8d9a87a2d7986adf38e724fbe47f15752d0931f14d8",
  "0x01e8677aa02546bd7105a7a9fd31c4ef16b69d1bde90f36e97585d7cc31d50e4",
  "0x2520a755a532994c78f35b89938fbc864ec31ec4fc00363f83f9b12f04980c6a",
  "0x21a666842842d5323e51fdda10300c763d6b07e1b797ef3b0bd3690d667445bc",
  "0x1ce681d6f42b70668c369e7f786166e421dc840f0529bbd065d6b02d14ae0fe8",
  "0x1819b90a43ee28f652735708b2ef01428e21b84872bb3c7576de6e35d107c8ed",
  "0x063d7001431110a5949f5946a501fd28f64159f36ab4b80601ca305ac107b3db",
  "0x09aeef7a06f7daf368d797c2e686c7e9884f000de0bd9d8e73392378b0b1be38",
  "0x137121fd5d795eeecc61ec6a6de66abc589d241540139178cd5408b6ccb32a6e",
  "0x01a93f70a1b7482e0b32e76ce49a1e3c1fc2b5cd4789b6af749d78c42791c21a",
  "0x217bf2cc1f1b505a29b162a7889866af2728f5c6708560c9cc5e987b194c9c81",
  '0x1461dae57d7df7e580279637e5d94e0d734b908dc22aec5c52ed00187050a030',
  "0x295933dd65294cbf4b2c64d8a0daa6983d35d1f64d5adc2c44bd9d370086d7dc",
  "0x24650084f0db0fa4e8234fb251ad046b3ddcb7d6f59160b35cc4086e9e196b80",
  "0x15086d0394bd68847e3e36241cc7b3966f96efdd30a37e9e1e85027a6dacbed2",
  "0x1f87a17564f06581c1e1b2d716120990f898893ecc0e076363c56c5e3b56ef7b"
]


export const tx_vk = txVk.slice(1)
export const tx_vk_hash = txVk[0]

export type GlobalConfig = {
  signer?: EthersSigner,
  anonRPC?: string, 
  nargo?: string, 
  profit?: number,
  coinbase?: number, 
  gossip?: GossipConfig, 
  withdrawal?: string, 
  verbose?: boolean,
  threads?: number,
  ip?: string,
  provider: Provider
}

export type GossipConfig = {
  seeds: string[];
  relays: string[];
  maxRelays: number;
}

export type Contracts = {
  state: Momiji,
  verifier: UltraVerifier,
  token: XFTMock,
  pool: IUniswapV3Pool
}

export type Circuits = {
  [key: string]: CompiledCircuit;
}

export type Backends = {
  [key: string]: BarretenbergBackend;
};

export type Noirs = {
  [key: string]: Noir;
};

export type CircuitsAndContracts = {
  circuits: Circuits;
  backends: Backends;
  noirs: Noirs;
  contracts: Contracts;
}

export type NoirJSProofData = ProofData

export type ProofArtifacts = {
  proofData: ProofData;
  proofAsFields: string[];
  vkAsFields: string[];
  vkHash: string;
}

export type GossipArtifacts = {
  proofData: ProofData;
  proofAsFields: string[];
}

export type MerkleProofInput = {
  tree: MerkleTree,
  leaf: Field
}

export interface UTXO_Commitment extends UTXO_New {
  commitment?: Field,
  siblings?: string[];
  spend_in_same_batch?: boolean
}

export type UTXO_Input = {
  secret?: string,
  amount: string,
  asset_type?: string
}

export interface UTXO_Encrypted extends UTXO_New {
  secret_encrypted: string;
  amount_encrypted: string;
  asset_type_encrypted: string;
  uid: string;
}

export type Withdrawal = {
  amount: Field;
  recipient: string;
  swap_percentage: number;
}

export interface WithdrawalSwap extends Withdrawal {
  swap_amount: string;
  price_limit: string;
}

export type Profit = {
  wei: bigint;
  xft: bigint;
}

export type TransactionIO = {
  utxo_commitment: UTXO_Commitment[],
  utxo_encrypted: UTXO_Encrypted[],
  withdrawal: WithdrawalSwap[]
}

export type TransactionInputsRaw = {
  current_root: string;
  deposit_amount: string;
  withdrawals: string[];
  utxo_spendable: UTXO_Spendable[];
  utxo_new: UTXO_New[];
  contract_only_inputs: ContractOnlyInputs;
}

export type RecursionInputs = {
  recursion_verifier: Verifier | undefined,
  transaction: Transaction | undefined,
  accumulator: Field,
}

export type PublishInputs = {
  accumulator: Field;
  hist_tree_input: HistoricTreeInput;
  tx_verifier: VerifierTx;
  recursion_verifier: Verifier;
}

export type ContractPublish = {
  proof: string;
  batch: ContractBatch
}

export type Deposit = {
  signature: string;
  pi_hash: string;
}

export type EncryptedUTXO = {
  secret: string;
  amount: string;
  data: string;
}

export type RollupTransaction = {
  transaction: Transaction,
  rollup_artifacts: ProofArtifacts
}

export type Transaction = {
  public_inputs: PublicInputs,
  contract_inputs: TransactionStruct,
  proof_artifacts: ProofArtifacts
}

export type Batch = {
  tx_key_hash: string;
  recursive_key_hash: string;
  new_root: string;
  old_hist_root: string;
  new_hist_root: string;
  oracle: string;
  historic_path: string[];
  aggregation_object: string[];
  transactions: ContractTransaction[];
}

export type TypedDataLabels = {
  name: string;
  type: string;
}

export type TypedDataTypes = {
  DepositHash: TypedDataLabels[]
}

export type TypedDataValues = {
  pi_hash: string
}

export interface Mempool {
  [key: string]: Transaction;
}

export interface Confirmed {
  [key: string]: boolean;
}

export interface Proven {
  [key: string]: boolean;
}



export interface Asset {

  assetContract: string;
  chainlink: string; 
  chainlinkDecimals: number;
  uniswap: string; 
  flags: number; 

}

export interface Prices {
  assetHash: number[]; 
  chainlink: number[]; 
  chainlinkDecimals: number[]; 
  uniswap: number[]; 
}


export function toFixedHex(number: number, pad0x: boolean, length: number = 32): string {
  let hexString = number.toString(16).padStart(length * 2, '0');
  return (pad0x ? `0x` + hexString : hexString);
}

export function stringToKeccak(_string: string): string {
  const bytes: Uint8Array = ethers.toUtf8Bytes(_string)
  const keccak: string = ethers.keccak256(bytes)
  return keccak
}

export function toResult(e: EthersEventLog): EthersEventResult { return (e as EthersEventLog).args[0] as EthersEventResult }
export function generateSecret(): string {
  return Fr.random().toString();
}