package keeper

import (
	"math/big"
	"testing"
)

func TestDefaultGasConfig_IsGasFree(t *testing.T) {
	config := DefaultGasConfig()
	keeper := NewEVMKeeper(config)

	if !keeper.IsGasFree() {
		t.Fatal("default config should be gas-free (platform subsidy)")
	}
}

func TestGetBaseFee_ReturnsZeroWhenFree(t *testing.T) {
	keeper := NewEVMKeeper(DefaultGasConfig())
	fee := keeper.GetBaseFee()

	if fee.Sign() != 0 {
		t.Fatalf("base fee should be 0, got %s", fee.String())
	}
}

func TestGetBaseFee_ReturnsMinGasPriceWhenSet(t *testing.T) {
	keeper := NewEVMKeeper(DefaultGasConfig())
	keeper.SetMinGasPrice(big.NewInt(1000))

	fee := keeper.GetBaseFee()
	if fee.Cmp(big.NewInt(1000)) != 0 {
		t.Fatalf("expected 1000, got %s", fee.String())
	}
}

func TestGetBaseFee_EIP1559Mode(t *testing.T) {
	keeper := NewEVMKeeper(DefaultGasConfig())
	keeper.SetMinGasPrice(big.NewInt(500))
	keeper.EnableEIP1559(true)

	fee := keeper.GetBaseFee()
	// In current implementation, EIP-1559 returns min gas price
	if fee.Cmp(big.NewInt(500)) != 0 {
		t.Fatalf("EIP-1559 base fee should be min gas price, got %s", fee.String())
	}
}

func TestSetMinGasPrice(t *testing.T) {
	keeper := NewEVMKeeper(DefaultGasConfig())

	keeper.SetMinGasPrice(big.NewInt(2000))

	price := keeper.GetMinGasPrice()
	if price.Cmp(big.NewInt(2000)) != 0 {
		t.Fatalf("expected 2000, got %s", price.String())
	}
	if keeper.IsGasFree() {
		t.Fatal("should not be gas-free after setting min gas price")
	}
}

func TestSetMinGasPriceBackToZero(t *testing.T) {
	keeper := NewEVMKeeper(DefaultGasConfig())
	keeper.SetMinGasPrice(big.NewInt(1000))
	keeper.SetMinGasPrice(big.NewInt(0))

	if !keeper.IsGasFree() {
		t.Fatal("should be gas-free after setting price back to 0")
	}
}

func TestGetMaxGasPerBlock(t *testing.T) {
	keeper := NewEVMKeeper(DefaultGasConfig())

	maxGas := keeper.GetMaxGasPerBlock()
	if maxGas != 100_000_000 {
		t.Fatalf("expected 100M, got %d", maxGas)
	}
}

func TestSetMaxGasPerBlock(t *testing.T) {
	keeper := NewEVMKeeper(DefaultGasConfig())
	keeper.SetMaxGasPerBlock(200_000_000)

	if keeper.GetMaxGasPerBlock() != 200_000_000 {
		t.Fatalf("expected 200M, got %d", keeper.GetMaxGasPerBlock())
	}
}

func TestEstimateGasCost_FreeMode(t *testing.T) {
	keeper := NewEVMKeeper(DefaultGasConfig())

	cost := keeper.EstimateGasCost(21000) // standard ETH transfer
	if cost.Sign() != 0 {
		t.Fatalf("gas cost should be 0 in free mode, got %s", cost.String())
	}
}

func TestEstimateGasCost_PaidMode(t *testing.T) {
	keeper := NewEVMKeeper(DefaultGasConfig())
	keeper.SetMinGasPrice(big.NewInt(10)) // 10 wei

	cost := keeper.EstimateGasCost(21000)
	expected := big.NewInt(210000) // 10 * 21000
	if cost.Cmp(expected) != 0 {
		t.Fatalf("expected %s, got %s", expected.String(), cost.String())
	}
}

func TestGetGasConfig(t *testing.T) {
	keeper := NewEVMKeeper(DefaultGasConfig())

	config := keeper.GetGasConfig()
	if config.MaxGasPerBlock != 100_000_000 {
		t.Fatal("config MaxGasPerBlock mismatch")
	}
	if config.EnableEIP1559 {
		t.Fatal("EIP-1559 should be disabled by default")
	}
	if config.BaseFeeChangeDenominator != 8 {
		t.Fatal("BaseFeeChangeDenominator mismatch")
	}
	if config.ElasticityMultiplier != 2 {
		t.Fatal("ElasticityMultiplier mismatch")
	}
}

func TestEnableEIP1559(t *testing.T) {
	keeper := NewEVMKeeper(DefaultGasConfig())

	keeper.EnableEIP1559(true)
	config := keeper.GetGasConfig()
	if !config.EnableEIP1559 {
		t.Fatal("EIP-1559 should be enabled")
	}

	keeper.EnableEIP1559(false)
	config = keeper.GetGasConfig()
	if config.EnableEIP1559 {
		t.Fatal("EIP-1559 should be disabled")
	}
}

func TestMinGasPrice_IsolatedCopy(t *testing.T) {
	keeper := NewEVMKeeper(DefaultGasConfig())
	keeper.SetMinGasPrice(big.NewInt(1000))

	// Get price and modify the returned value
	price := keeper.GetMinGasPrice()
	price.SetInt64(9999)

	// Original should not be affected
	original := keeper.GetMinGasPrice()
	if original.Cmp(big.NewInt(1000)) != 0 {
		t.Fatal("GetMinGasPrice should return a copy, not a reference")
	}
}
