package native_test

import (
	"testing"

	"github.com/stretchr/testify/require"
	"git.marketally.com/tutus-one/tutus-chain/pkg/core/native/nativenames"
	"git.marketally.com/tutus-one/tutus-chain/pkg/core/state"
	"git.marketally.com/tutus-one/tutus-chain/pkg/tutustest"
	"git.marketally.com/tutus-one/tutus-chain/pkg/vm/stackitem"
)

func newEligereClient(t *testing.T) *tutustest.ContractInvoker {
	return newNativeClient(t, nativenames.Eligere)
}

// TestEligere_GetConfig tests the getConfig method.
func TestEligere_GetConfig(t *testing.T) {
	c := newEligereClient(t)

	// Get default config
	c.InvokeAndCheck(t, func(t testing.TB, stack []stackitem.Item) {
		require.Equal(t, 1, len(stack))
		arr, ok := stack[0].Value().([]stackitem.Item)
		require.True(t, ok, "expected array result")
		require.GreaterOrEqual(t, len(arr), 7) // EligereConfig has 7 fields
	}, "getConfig")
}

// TestEligere_GetProposalCount tests the getProposalCount method.
func TestEligere_GetProposalCount(t *testing.T) {
	c := newEligereClient(t)

	// Initially should be 0
	c.Invoke(t, 0, "getProposalCount")
}

// TestEligere_GetProposal_NonExistent tests getting a non-existent proposal.
func TestEligere_GetProposal_NonExistent(t *testing.T) {
	c := newEligereClient(t)

	// Non-existent proposal should return null
	c.InvokeAndCheck(t, func(t testing.TB, stack []stackitem.Item) {
		require.Equal(t, 1, len(stack))
		require.Nil(t, stack[0].Value(), "expected null for non-existent proposal")
	}, "getProposal", 999)
}

// TestEligere_CreateProposal_NoVita tests that creating a proposal without a Vita fails.
func TestEligere_CreateProposal_NoVita(t *testing.T) {
	c := newEligereClient(t)
	e := c.Executor

	acc := e.NewAccount(t)
	invoker := c.WithSigners(acc)

	title := "Test Proposal"
	contentHash := make([]byte, 32) // 32-byte hash
	category := int64(state.ProposalCategoryLawAmendment)
	votingStartsAt := int64(10)
	votingEndsAt := int64(100)
	targetContract := make([]byte, 20) // 20-byte Uint160

	// Should fail - no Vita registered
	invoker.InvokeFail(t, "caller must have active Vita", "createProposal",
		title, contentHash, category, votingStartsAt, votingEndsAt,
		targetContract, "", []byte{})
}

// Note: TestEligere_CreateProposal_Success is skipped because it requires a deployed
// helper contract with a Vita registered to its script hash. The Eligere contract uses
// GetCallingScriptHash() which returns the transaction script for direct calls.

// TestEligere_HasVoted_NoVote tests hasVoted returns false when not voted.
func TestEligere_HasVoted_NoVote(t *testing.T) {
	c := newEligereClient(t)
	e := c.Executor

	acc := e.NewAccount(t)

	// hasVoted should return false for any proposal when no vote cast
	c.Invoke(t, false, "hasVoted", 0, acc.ScriptHash())
}

// TestEligere_Vote_NoVita tests voting without a Vita fails.
func TestEligere_Vote_NoVita(t *testing.T) {
	c := newEligereClient(t)
	e := c.Executor

	acc := e.NewAccount(t)
	invoker := c.WithSigners(acc)

	// Try to vote without Vita
	invoker.InvokeFail(t, "caller must have active Vita", "vote", 0, int64(state.VoteChoiceYes))
}

// Note: Testing createProposal, vote, tallyVotes, and executeProposal with actual Vita
// holders requires deploying a helper contract that has a Vita registered to its script
// hash and then making cross-contract calls. The Eligere contract uses GetCallingScriptHash()
// which returns the transaction script hash for direct calls, not the signer's account.
// This is the intended design for cross-contract authorization patterns.
