package simulation

import (
	"math/rand"
	"strconv"

	"electra/x/meter/keeper"
	"electra/x/meter/types"
	"github.com/cosmos/cosmos-sdk/baseapp"
	simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
	sdk "github.com/cosmos/cosmos-sdk/types"
	simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
	"github.com/cosmos/cosmos-sdk/x/simulation"
)

// Prevent strconv unused error
var _ = strconv.IntSize

func SimulateMsgCreatePpaMap(
	ak types.AccountKeeper,
	bk types.BankKeeper,
	k keeper.Keeper,
) simtypes.Operation {
	return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
		simAccount, _ := simtypes.RandomAcc(r, accs)

		i := r.Int()
		msg := &types.MsgCreatePpaMap{
			Creator:          simAccount.Address.String(),
			ConsumerDeviceID: strconv.Itoa(i),
			AgreementID:      strconv.Itoa(i),
			AgreementActive:  false,
			ContractID:       strconv.Itoa(i),
		}

		_, found := k.GetPpaMap(ctx, msg.ConsumerDeviceID, msg.AgreementID, msg.AgreementActive, msg.ContractID)
		if found {
			return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "PpaMap already exist"), nil, nil
		}

		txCtx := simulation.OperationInput{
			R:               r,
			App:             app,
			TxGen:           simappparams.MakeTestEncodingConfig().TxConfig,
			Cdc:             nil,
			Msg:             msg,
			MsgType:         msg.Type(),
			Context:         ctx,
			SimAccount:      simAccount,
			ModuleName:      types.ModuleName,
			CoinsSpentInMsg: sdk.NewCoins(),
			AccountKeeper:   ak,
			Bankkeeper:      bk,
		}
		return simulation.GenAndDeliverTxWithRandFees(txCtx)
	}
}

func SimulateMsgUpdatePpaMap(
	ak types.AccountKeeper,
	bk types.BankKeeper,
	k keeper.Keeper,
) simtypes.Operation {
	return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
		var (
			simAccount = simtypes.Account{}
			ppaMap     = types.PpaMap{}
			msg        = &types.MsgUpdatePpaMap{}
			allPpaMap  = k.GetAllPpaMap(ctx)
			found      = false
		)
		for _, obj := range allPpaMap {
			simAccount, found = FindAccount(accs, obj.Creator)
			if found {
				ppaMap = obj
				break
			}
		}
		if !found {
			return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "ppaMap creator not found"), nil, nil
		}
		msg.Creator = simAccount.Address.String()

		msg.ConsumerDeviceID = ppaMap.ConsumerDeviceID
		msg.AgreementID = ppaMap.AgreementID
		msg.AgreementActive = ppaMap.AgreementActive
		msg.ContractID = ppaMap.ContractID

		txCtx := simulation.OperationInput{
			R:               r,
			App:             app,
			TxGen:           simappparams.MakeTestEncodingConfig().TxConfig,
			Cdc:             nil,
			Msg:             msg,
			MsgType:         msg.Type(),
			Context:         ctx,
			SimAccount:      simAccount,
			ModuleName:      types.ModuleName,
			CoinsSpentInMsg: sdk.NewCoins(),
			AccountKeeper:   ak,
			Bankkeeper:      bk,
		}
		return simulation.GenAndDeliverTxWithRandFees(txCtx)
	}
}

func SimulateMsgDeletePpaMap(
	ak types.AccountKeeper,
	bk types.BankKeeper,
	k keeper.Keeper,
) simtypes.Operation {
	return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
		var (
			simAccount = simtypes.Account{}
			ppaMap     = types.PpaMap{}
			msg        = &types.MsgUpdatePpaMap{}
			allPpaMap  = k.GetAllPpaMap(ctx)
			found      = false
		)
		for _, obj := range allPpaMap {
			simAccount, found = FindAccount(accs, obj.Creator)
			if found {
				ppaMap = obj
				break
			}
		}
		if !found {
			return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "ppaMap creator not found"), nil, nil
		}
		msg.Creator = simAccount.Address.String()

		msg.ConsumerDeviceID = ppaMap.ConsumerDeviceID
		msg.AgreementID = ppaMap.AgreementID
		msg.AgreementActive = ppaMap.AgreementActive
		msg.ContractID = ppaMap.ContractID

		txCtx := simulation.OperationInput{
			R:               r,
			App:             app,
			TxGen:           simappparams.MakeTestEncodingConfig().TxConfig,
			Cdc:             nil,
			Msg:             msg,
			MsgType:         msg.Type(),
			Context:         ctx,
			SimAccount:      simAccount,
			ModuleName:      types.ModuleName,
			CoinsSpentInMsg: sdk.NewCoins(),
			AccountKeeper:   ak,
			Bankkeeper:      bk,
		}
		return simulation.GenAndDeliverTxWithRandFees(txCtx)
	}
}
