package tradingvolume

import (
	"fmt"
	"testing"

	"github.com/brevis-network/brevis-sdk/sdk"
	"github.com/brevis-network/brevis-sdk/test"
	"github.com/ethereum/go-ethereum/common"
)

// In this example, we want to analyze the `Swap` events emitted by Uniswap's
// UniversalRouter contract. Let's declare the fields we want to use:

func TestCircuit(t *testing.T) {
	rpc := "RPC_URL"
	outDir := "$HOME/circuitOut/myBrevisApp"
	app, err := sdk.NewBrevisApp(1, rpc, outDir)
	check(err)

	// Adding a receipt query into the querier
	// In this tx, the user sold USDC and took native ETH out
	app.AddReceipt(sdk.ReceiptData{
		TxHash: common.HexToHash("53b37ec7975d217295f4bdadf8043b261fc49dccc16da9b9fc8b9530845a5794"),
		Fields: []sdk.LogFieldData{
			{LogPos: 3, IsTopic: false, FieldIndex: 0}, // field: USDCPool.Swap.amount0
			{LogPos: 3, IsTopic: true, FieldIndex: 2},  // field: USDCPool.Swap.recipient (topic field)
			{LogPos: 2, IsTopic: true, FieldIndex: 1},  // field: USDC.Transfer.from
		},
	})
	// More receipts can be added, but in this example we only add one to keep it simple
	// app.AddReceipt(...)
	// app.AddReceipt(...)

	// Initialize our AppCircuit and prepare the circuit assignment
	appCircuit := &AppCircuit{
		UserAddr: sdk.ConstUint248(common.HexToAddress("0xaefB31e9EEee2822f4C1cBC13B70948b0B5C0b3c")),
	}
	appCircuitAssignment := &AppCircuit{
		UserAddr: sdk.ConstUint248(common.HexToAddress("0xaefB31e9EEee2822f4C1cBC13B70948b0B5C0b3c")),
	}

	// Execute the added queries and package the query results into circuit inputs
	in, err := app.BuildCircuitInput(appCircuit)
	check(err)

	///////////////////////////////////////////////////////////////////////////////
	// Testing
	///////////////////////////////////////////////////////////////////////////////

	// Use the test package to check if the circuit can be solved using the given
	// assignment
	test.ProverSucceeded(t, appCircuit, appCircuitAssignment, in)
}

func TestE2E(t *testing.T) {
	// The compiled circuit, proving key, and verifying key are saved to outDir,,
	// query data will be stored under outDir/input and
	// the downloaded SRS in the process is saved to srsDir
	outDir := "$HOME/circuitOut/tradingvolume"
	srsDir := "$HOME/kzgsrs"
	rpc := "RPC_URL"
	app, err := sdk.NewBrevisApp(1, rpc, outDir)
	check(err)

	// Adding a receipt query into the querier
	// In this tx, the user sold USDC and took native ETH out
	app.AddReceipt(sdk.ReceiptData{
		TxHash: common.HexToHash("53b37ec7975d217295f4bdadf8043b261fc49dccc16da9b9fc8b9530845a5794"),
		Fields: []sdk.LogFieldData{
			{LogPos: 3, IsTopic: false, FieldIndex: 0}, // field: USDCPool.Swap.amount0
			{LogPos: 3, IsTopic: true, FieldIndex: 2},  // field: USDCPool.Swap.recipient (topic field)
			{LogPos: 2, IsTopic: true, FieldIndex: 1},  // field: USDC.Transfer.from
		},
	})
	// More receipts can be added, but in this example we only add one to keep it simple
	// app.AddReceipt(...)
	// app.AddReceipt(...)

	// Initialize our AppCircuit and prepare the circuit assignment
	appCircuit := &AppCircuit{
		// you need to give every custom input an assignment or otherwise the circuit won't compile
		UserAddr: sdk.ConstUint248(0),
	}
	appCircuitAssignment := &AppCircuit{
		UserAddr: sdk.ConstUint248(common.HexToAddress("0xaefB31e9EEee2822f4C1cBC13B70948b0B5C0b3c")),
	}

	// Execute the added queries and package the query results into circuit inputs
	in, err := app.BuildCircuitInput(appCircuitAssignment)
	check(err)

	///////////////////////////////////////////////////////////////////////////////
	// Testing
	///////////////////////////////////////////////////////////////////////////////

	// Use the test package to check if the input can be proved with the given
	// circuit
	test.ProverSucceeded(t, appCircuit, appCircuitAssignment, in)

	///////////////////////////////////////////////////////////////////////////////
	// Compiling and Setup
	///////////////////////////////////////////////////////////////////////////////

	compiledCircuit, pk, vk, _, err := sdk.Compile(appCircuit, outDir, srsDir, app)
	check(err)

	// Once you saved your ccs, pk, and vk files, you can read them back into memory
	// for use with the provided utils
	compiledCircuit, pk, vk, _, err = sdk.ReadSetupFrom(appCircuit, outDir, app)
	check(err)

	///////////////////////////////////////////////////////////////////////////////
	// Proving
	///////////////////////////////////////////////////////////////////////////////

	fmt.Println(">> prove")
	witness, publicWitness, err := sdk.NewFullWitness(appCircuitAssignment, in)
	check(err)
	proof, err := sdk.Prove(compiledCircuit, pk, witness)
	check(err)

	///////////////////////////////////////////////////////////////////////////////
	// Verifying
	///////////////////////////////////////////////////////////////////////////////

	// The verification of the proof generated by you is done on Brevis' side. But
	// you can also verify your own proof to make sure everything works fine and
	// pk/vk are serialized/deserialized properly
	err = sdk.Verify(vk, publicWitness, proof)
	check(err)
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}
