// Copyright (c) 2017-2026 Lethean (https://lt.hn)
//
// Licensed under the European Union Public Licence (EUPL) version 1.2.
// SPDX-License-Identifier: EUPL-1.2

package config

import (
	"testing"
)

func TestVersionAtHeight_Good(t *testing.T) {
	tests := []struct {
		name    string
		height  uint64
		want    uint8
	}{
		// Genesis block should return HF0 (the initial version).
		{"genesis", 0, HF0Initial},

		// Just before HF1/HF2 activation on mainnet (height 10080).
		// HF1 activates at heights > 10080, so height 10080 is still HF0.
		{"before_hf1", 10080, HF0Initial},

		// At height 10081, both HF1 and HF2 activate (both have height 10080).
		// The highest version wins.
		{"at_hf1_hf2", 10081, HF2},

		// Well past HF2 but before any future forks.
		{"mid_chain", 50000, HF2},

		// Far future but still below 999999999 — should still be HF2.
		{"high_but_before_future", 999999999, HF2},

		// At height 1000000000 (> 999999999), all future forks activate.
		{"all_forks_active", 1000000000, HF6},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := VersionAtHeight(MainnetForks, tt.height)
			if got != tt.want {
				t.Errorf("VersionAtHeight(MainnetForks, %d) = %d, want %d", tt.height, got, tt.want)
			}
		})
	}
}

func TestVersionAtHeightTestnet_Good(t *testing.T) {
	tests := []struct {
		name   string
		height uint64
		want   uint8
	}{
		// On testnet, HF0, HF1, and HF3 all have Height=0 so they are
		// active from genesis. The highest version at genesis is HF3.
		{"genesis", 0, HF3},

		// At height 10, HF2 is still not active (activates at > 10).
		{"before_hf2", 10, HF3},

		// At height 11, HF2 activates — but HF3 is already active so
		// the version remains 3.
		{"after_hf2", 11, HF3},

		// At height 101, HF4 Zarcanum activates.
		{"after_hf4", 101, HF4Zarcanum},

		// At height 201, HF5 activates.
		{"after_hf5", 201, HF5},

		// Far future activates HF6.
		{"far_future", 1000000000, HF6},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := VersionAtHeight(TestnetForks, tt.height)
			if got != tt.want {
				t.Errorf("VersionAtHeight(TestnetForks, %d) = %d, want %d", tt.height, got, tt.want)
			}
		})
	}
}

func TestIsHardForkActive_Good(t *testing.T) {
	tests := []struct {
		name    string
		version uint8
		height  uint64
		want    bool
	}{
		// HF0 is always active (Height=0).
		{"hf0_at_genesis", HF0Initial, 0, true},
		{"hf0_at_10000", HF0Initial, 10000, true},

		// HF1 activates at heights > 10080.
		{"hf1_before", HF1, 10080, false},
		{"hf1_at", HF1, 10081, true},

		// HF4 is far future on mainnet.
		{"hf4_now", HF4Zarcanum, 50000, false},
		{"hf4_far_future", HF4Zarcanum, 1000000000, true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := IsHardForkActive(MainnetForks, tt.version, tt.height)
			if got != tt.want {
				t.Errorf("IsHardForkActive(MainnetForks, %d, %d) = %v, want %v",
					tt.version, tt.height, got, tt.want)
			}
		})
	}
}

func TestIsHardForkActive_Bad(t *testing.T) {
	// Querying a version that does not exist should return false.
	got := IsHardForkActive(MainnetForks, 99, 1000000000)
	if got {
		t.Error("IsHardForkActive with unknown version should return false")
	}
}

func TestVersionAtHeight_Ugly(t *testing.T) {
	// Empty fork list should return version 0.
	got := VersionAtHeight(nil, 100)
	if got != 0 {
		t.Errorf("VersionAtHeight(nil, 100) = %d, want 0", got)
	}

	// Single-element fork list.
	single := []HardFork{{Version: 1, Height: 0, Mandatory: true}}
	got = VersionAtHeight(single, 0)
	if got != 1 {
		t.Errorf("VersionAtHeight(single, 0) = %d, want 1", got)
	}
}

func TestMainnetForkSchedule_Good(t *testing.T) {
	// Verify the fork schedule matches the C++ ZANO_HARDFORK_* constants.
	expectedMainnet := []struct {
		version uint8
		height  uint64
	}{
		{0, 0},
		{1, 10080},
		{2, 10080},
		{3, 999999999},
		{4, 999999999},
		{5, 999999999},
		{6, 999999999},
	}

	if len(MainnetForks) != len(expectedMainnet) {
		t.Fatalf("MainnetForks length: got %d, want %d", len(MainnetForks), len(expectedMainnet))
	}

	for i, exp := range expectedMainnet {
		hf := MainnetForks[i]
		if hf.Version != exp.version {
			t.Errorf("MainnetForks[%d].Version = %d, want %d", i, hf.Version, exp.version)
		}
		if hf.Height != exp.height {
			t.Errorf("MainnetForks[%d].Height = %d, want %d", i, hf.Height, exp.height)
		}
	}
}

func TestTestnetForkSchedule_Good(t *testing.T) {
	expectedTestnet := []struct {
		version uint8
		height  uint64
	}{
		{0, 0},
		{1, 0},
		{2, 10},
		{3, 0},
		{4, 100},
		{5, 200},
		{6, 999999999},
	}

	if len(TestnetForks) != len(expectedTestnet) {
		t.Fatalf("TestnetForks length: got %d, want %d", len(TestnetForks), len(expectedTestnet))
	}

	for i, exp := range expectedTestnet {
		hf := TestnetForks[i]
		if hf.Version != exp.version {
			t.Errorf("TestnetForks[%d].Version = %d, want %d", i, hf.Version, exp.version)
		}
		if hf.Height != exp.height {
			t.Errorf("TestnetForks[%d].Height = %d, want %d", i, hf.Height, exp.height)
		}
	}
}
