package initialize

import (
	"github.com/argus-labs/darkfrontier-backend/circuit"
	"math/big"
	"testing"

	"github.com/argus-labs/darkfrontier-backend/circuit/perlin"
	"github.com/consensys/gnark-crypto/ecc"
	"github.com/consensys/gnark/backend"
	"github.com/consensys/gnark/test"
)

var (
	initCircuit InitCircuit
	pub         *big.Int
)

func init() {
	initCircuit.PlanetHashKey = circuit.PlanetHashKey
	initCircuit.SpaceTypeKey = circuit.SpaceTypeKey

	var ok bool
	// Generated by MiMCSharp
	pub, ok = new(big.Int).SetString("0d01f8778431d6f04310bf3f02fb6e85a173624241fc8d8185c528306f57ca68", 16)
	if !ok {
		panic("failed to parse big.Int from MiMCSharp string output")
	}
}

func TestInit(t *testing.T) {
	assert := test.NewAssert(t)

	assert.ProverSucceeded(
		&initCircuit,
		&InitCircuit{
			X:       3,
			Y:       -3,
			R:       circuit.RadiusMax,
			Scale:   circuit.Scale,
			XMirror: circuit.XMirror,
			YMirror: circuit.YMirror,
			Pub:     pub,
			Perl:    16,
		},
		test.WithProverOpts(backend.WithHints(perlin.ModuloHint)),
		test.WithBackends(backend.GROTH16),
		test.WithCurves(ecc.BN254),
	)
}

func TestInitFuzz(t *testing.T) {
	assert := test.NewAssert(t)

	assert.Fuzz(
		&initCircuit,
		100,
		test.WithProverOpts(backend.WithHints(perlin.ModuloHint)),
		test.WithBackends(backend.GROTH16),
		test.WithCurves(ecc.BN254),
	)
}

// Test that the circuit fails when the new point is outside the circular boundary:
// x^2 + y^2 < r^2
func TestMoveNewPointOutsideCircularBoundary(t *testing.T) {
	assert := test.NewAssert(t)

	assert.ProverFailed(
		&initCircuit,
		&InitCircuit{
			X:       300,
			Y:       300,
			R:       circuit.RadiusMax,
			Scale:   circuit.Scale,
			XMirror: circuit.XMirror,
			YMirror: circuit.YMirror,
			Pub:     pub,
			Perl:    16,
		},
		test.WithProverOpts(backend.WithHints(perlin.ModuloHint)),
		test.WithBackends(backend.GROTH16),
		test.WithCurves(ecc.BN254),
	)
}

// Test whether changing any of the X or Y values without changing the respective
// Pub1 or Pub2 variable will throw an error because of the following constraint:
// MiMCSponge(x,y) = pub
func TestMiMCConstraint(t *testing.T) {
	assert := test.NewAssert(t)

	assert.ProverFailed(
		&initCircuit,
		&InitCircuit{
			X:       3,
			Y:       -4, // Changed from -3 to -4
			R:       circuit.RadiusMax,
			Scale:   circuit.Scale,
			XMirror: circuit.XMirror,
			YMirror: circuit.YMirror,
			Pub:     pub,
			Perl:    16,
		},
		test.WithProverOpts(backend.WithHints(perlin.ModuloHint)),
		test.WithBackends(backend.GROTH16),
		test.WithCurves(ecc.BN254),
	)
}
