package app

// import (
// 	"encoding/json"
// 	"fmt"
// 	"os"
// 	"path/filepath"
// 	"testing"

// 	"cosmossdk.io/log"
// 	storetypes "cosmossdk.io/store/types"
// 	evidencetypes "cosmossdk.io/x/evidence/types"
// 	"cosmossdk.io/x/feegrant"
// 	tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
// 	dbm "github.com/cosmos/cosmos-db"
// 	"github.com/cosmos/cosmos-sdk/baseapp"
// 	"github.com/cosmos/cosmos-sdk/testutil/sims"
// 	sdk "github.com/cosmos/cosmos-sdk/types"
// 	"github.com/cosmos/cosmos-sdk/types/kv"
// 	simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
// 	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
// 	authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper"
// 	banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
// 	distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
// 	govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
// 	minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
// 	paramstypes "github.com/cosmos/cosmos-sdk/x/params/types"
// 	"github.com/cosmos/cosmos-sdk/x/simulation"
// 	simcli "github.com/cosmos/cosmos-sdk/x/simulation/client/cli"
// 	slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
// 	stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
// 	capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types"
// 	ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
// 	ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported"
// 	"github.com/stretchr/testify/require"

// 	wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
// )

// // Get flags every time the simulator is run
// func init() {
// 	simcli.GetSimulatorFlags()
// }

// type StoreKeysPrefixes struct {
// 	A        storetypes.StoreKey
// 	B        storetypes.StoreKey
// 	Prefixes [][]byte
// }

// // SetupSimulation wraps simapp.SetupSimulation in order to create any export directory if they do not exist yet
// func SetupSimulation(dirPrefix, dbName string) (simtypes.Config, dbm.DB, string, log.Logger, bool, error) {
// 	config := simcli.NewConfigFromFlags()
// 	db, dir, logger, skip, err := sims.SetupSimulation(config, dirPrefix, dbName, simcli.FlagVerboseValue, simcli.FlagEnabledValue)
// 	if err != nil {
// 		return simtypes.Config{}, nil, "", nil, false, err
// 	}

// 	paths := []string{config.ExportParamsPath, config.ExportStatePath, config.ExportStatsPath}
// 	for _, path := range paths {
// 		if len(path) == 0 {
// 			continue
// 		}

// 		path = filepath.Dir(path)
// 		if _, err := os.Stat(path); os.IsNotExist(err) {
// 			if err := os.MkdirAll(path, os.ModePerm); err != nil {
// 				panic(err)
// 			}
// 		}
// 	}

// 	return config, db, dir, logger, skip, err
// }

// // GetSimulationLog unmarshals the KVPair's Value to the corresponding type based on the
// // each's module store key and the prefix bytes of the KVPair's key.
// func GetSimulationLog(storeName string, sdr sdk.StoreDecoderRegistry, kvAs, kvBs []kv.Pair) (log string) {
// 	for i := 0; i < len(kvAs); i++ {
// 		if len(kvAs[i].Value) == 0 && len(kvBs[i].Value) == 0 {
// 			// skip if the value doesn't have any bytes
// 			continue
// 		}

// 		decoder, ok := sdr[storeName]
// 		if ok {
// 			log += decoder(kvAs[i], kvBs[i])
// 		} else {
// 			log += fmt.Sprintf("store A %q => %q\nstore B %q => %q\n", kvAs[i].Key, kvAs[i].Value, kvBs[i].Key, kvBs[i].Value)
// 		}
// 	}

// 	return log
// }

// // fauxMerkleModeOpt returns a BaseApp option to use a dbStoreAdapter instead of
// // an IAVLStore for faster simulation speed.
// func fauxMerkleModeOpt(bapp *baseapp.BaseApp) {
// 	bapp.SetFauxMerkleMode()
// }

// func TestAppImportExport(t *testing.T) {
// 	config, db, dir, logger, skip, err := SetupSimulation("leveldb-app-sim", "Simulation")
// 	if skip {
// 		t.Skip("skipping application import/export simulation")
// 	}
// 	require.NoError(t, err, "simulation setup failed")

// 	defer func() {
// 		db.Close()
// 		require.NoError(t, os.RemoveAll(dir))
// 	}()

// 	encConf := MakeEncodingConfig()
// 	app := NewArchwayApp(logger, db, nil, true, map[int64]bool{}, dir, simcli.FlagPeriodValue, encConf, EmptyBaseAppOptions{}, nil, fauxMerkleModeOpt)
// 	require.Equal(t, appName, app.Name())

// 	// Run randomized simulation
// 	_, simParams, simErr := simulation.SimulateFromSeed(
// 		t,
// 		os.Stdout,
// 		app.BaseApp,
// 		sims.AppStateFn(app.AppCodec(), app.SimulationManager(), NewDefaultGenesisState(app.AppCodec())),
// 		simtypes.RandomAccounts,
// 		sims.SimulationOperations(app, app.AppCodec(), config),
// 		app.ModuleAccountAddrs(),
// 		config,
// 		app.AppCodec(),
// 	)

// 	// export state and simParams before the simulation error is checked
// 	err = sims.CheckExportSimulation(app, config, simParams)
// 	require.NoError(t, err)
// 	require.NoError(t, simErr)

// 	if config.Commit {
// 		sims.PrintStats(db)
// 	}

// 	t.Log("exporting genesis...")

// 	exported, err := app.ExportAppStateAndValidators(false, []string{}, []string{})
// 	require.NoError(t, err)

// 	t.Log("importing genesis...")

// 	_, newDB, newDir, _, _, err := SetupSimulation("leveldb-app-sim-2", "Simulation-2")
// 	require.NoError(t, err, "simulation setup failed")

// 	defer func() {
// 		newDB.Close()
// 		require.NoError(t, os.RemoveAll(newDir))
// 	}()
// 	newApp := NewArchwayApp(logger, newDB, nil, true, map[int64]bool{}, newDir, simcli.FlagPeriodValue, encConf, EmptyBaseAppOptions{}, nil, fauxMerkleModeOpt)
// 	require.Equal(t, appName, newApp.Name())

// 	var genesisState GenesisState
// 	err = json.Unmarshal(exported.AppState, &genesisState)
// 	require.NoError(t, err)

// 	ctxA := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()})
// 	ctxB := newApp.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()})
// 	newApp.mm.InitGenesis(ctxB, app.AppCodec(), genesisState)
// 	newApp.StoreConsensusParams(ctxB, exported.ConsensusParams)

// 	t.Log("comparing stores...")

// 	storeKeysPrefixes := []StoreKeysPrefixes{
// 		{app.keys[authtypes.StoreKey], newApp.keys[authtypes.StoreKey], [][]byte{}},
// 		{
// 			app.keys[stakingtypes.StoreKey], newApp.keys[stakingtypes.StoreKey],
// 			[][]byte{
// 				stakingtypes.UnbondingQueueKey, stakingtypes.RedelegationQueueKey, stakingtypes.ValidatorQueueKey,
// 				stakingtypes.HistoricalInfoKey,
// 			},
// 		},
// 		{app.keys[slashingtypes.StoreKey], newApp.keys[slashingtypes.StoreKey], [][]byte{}},
// 		{app.keys[minttypes.StoreKey], newApp.keys[minttypes.StoreKey], [][]byte{}},
// 		{app.keys[distrtypes.StoreKey], newApp.keys[distrtypes.StoreKey], [][]byte{}},
// 		{app.keys[banktypes.StoreKey], newApp.keys[banktypes.StoreKey], [][]byte{banktypes.BalancesPrefix}},
// 		{app.keys[paramstypes.StoreKey], newApp.keys[paramstypes.StoreKey], [][]byte{}},
// 		{app.keys[govtypes.StoreKey], newApp.keys[govtypes.StoreKey], [][]byte{}},
// 		{app.keys[evidencetypes.StoreKey], newApp.keys[evidencetypes.StoreKey], [][]byte{}},
// 		{app.keys[capabilitytypes.StoreKey], newApp.keys[capabilitytypes.StoreKey], [][]byte{}},
// 		{app.keys[ibcexported.StoreKey], newApp.keys[ibcexported.StoreKey], [][]byte{}},
// 		{app.keys[ibctransfertypes.StoreKey], newApp.keys[ibctransfertypes.StoreKey], [][]byte{}},
// 		{app.keys[authzkeeper.StoreKey], newApp.keys[authzkeeper.StoreKey], [][]byte{}},
// 		{app.keys[feegrant.StoreKey], newApp.keys[feegrant.StoreKey], [][]byte{}},
// 		{app.keys[wasmtypes.StoreKey], newApp.keys[wasmtypes.StoreKey], [][]byte{}},
// 	}

// 	// delete persistent tx counter value
// 	ctxA.KVStore(app.keys[wasmtypes.StoreKey]).Delete(wasmtypes.TXCounterPrefix)

// 	// diff both stores
// 	for _, skp := range storeKeysPrefixes {
// 		storeA := ctxA.KVStore(skp.A)
// 		storeB := ctxB.KVStore(skp.B)

// 		failedKVAs, failedKVBs := sdk.DiffKVStores(storeA, storeB, skp.Prefixes)
// 		require.Equal(t, len(failedKVAs), len(failedKVBs), "unequal sets of key-values to compare")

// 		t.Logf("compared %d different key/value pairs between %s and %s\n", len(failedKVAs), skp.A, skp.B)
// 		require.Len(t, failedKVAs, 0, GetSimulationLog(skp.A.Name(), app.SimulationManager().StoreDecoders, failedKVAs, failedKVBs))
// 	}
// }

// func TestFullAppSimulation(t *testing.T) {
// 	config, db, dir, logger, skip, err := SetupSimulation("leveldb-app-sim", "Simulation")
// 	if skip {
// 		t.Skip("skipping application simulation")
// 	}
// 	require.NoError(t, err, "simulation setup failed")

// 	defer func() {
// 		db.Close()
// 		require.NoError(t, os.RemoveAll(dir))
// 	}()
// 	encConf := MakeEncodingConfig()
// 	app := NewArchwayApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, simcli.FlagPeriodValue,
// 		encConf, sims.EmptyAppOptions{}, nil, fauxMerkleModeOpt)
// 	require.Equal(t, "ArchwayApp", app.Name())

// 	// run randomized simulation
// 	_, simParams, simErr := simulation.SimulateFromSeed(
// 		t,
// 		os.Stdout,
// 		app.BaseApp,
// 		sims.AppStateFn(app.appCodec, app.SimulationManager(), NewDefaultGenesisState(app.AppCodec())),
// 		simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
// 		sims.SimulationOperations(app, app.AppCodec(), config),
// 		app.ModuleAccountAddrs(),
// 		config,
// 		app.AppCodec(),
// 	)

// 	// export state and simParams before the simulation error is checked
// 	err = sims.CheckExportSimulation(app, config, simParams)
// 	require.NoError(t, err)
// 	require.NoError(t, simErr)

// 	if config.Commit {
// 		sims.PrintStats(db)
// 	}
// }
