package bitcoin

import (
	"testing"

	"github.com/btcsuite/btcd/btcutil/hdkeychain"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/tyler-smith/go-bip39"
)

const (
	testMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
)

func TestDeriveAddresses(t *testing.T) {
	seed := bip39.NewSeed(testMnemonic, "")

	addresses, err := DeriveAddresses(seed, 5)
	if err != nil {
		t.Fatalf("DeriveAddresses failed: %v", err)
	}

	// We expect 5 addresses per path * 3 paths = 15 addresses
	expectedCount := 5 * len(StandardPaths)
	if len(addresses) != expectedCount {
		t.Errorf("Expected %d addresses, got %d", expectedCount, len(addresses))
	}

	// Test known addresses for the test mnemonic
	expectedAddresses := map[string]string{
		"m/44'/0'/0'/0/0": "1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA",
		"m/84'/0'/0'/0/0": "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu",
	}

	addressMap := make(map[string]string)
	for _, addr := range addresses {
		addressMap[addr.Path] = addr.Address
	}

	for path, expectedAddr := range expectedAddresses {
		if actualAddr, exists := addressMap[path]; !exists {
			t.Errorf("Address for path %s not found", path)
		} else if actualAddr != expectedAddr {
			t.Errorf("Address mismatch for path %s: expected %s, got %s", path, expectedAddr, actualAddr)
		}
	}
}

func TestDerivePathAddresses(t *testing.T) {
	seed := bip39.NewSeed(testMnemonic, "")
	masterKey, err := hdkeychain.NewMaster(seed, &chaincfg.MainNetParams)
	if err != nil {
		t.Fatalf("Failed to create master key: %v", err)
	}

	tests := []struct {
		path            DerivationPath
		addressIndex    int
		expectedAddress string
	}{
		{
			path:            StandardPaths[0], // BIP44
			addressIndex:    0,
			expectedAddress: "1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA",
		},
		{
			path:            StandardPaths[1], // BIP49
			addressIndex:    0,
			expectedAddress: "37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf",
		},
		{
			path:            StandardPaths[2], // BIP84
			addressIndex:    0,
			expectedAddress: "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu",
		},
	}

	for _, tt := range tests {
		t.Run(tt.path.Name, func(t *testing.T) {
			addresses, err := derivePathAddresses(masterKey, tt.path, 5)
			if err != nil {
				t.Fatalf("derivePathAddresses failed: %v", err)
			}

			if len(addresses) != 5 {
				t.Errorf("Expected 5 addresses, got %d", len(addresses))
			}

			if addresses[tt.addressIndex].Address != tt.expectedAddress {
				t.Errorf("Address mismatch: expected %s, got %s",
					tt.expectedAddress, addresses[tt.addressIndex].Address)
			}
		})
	}
}

func TestDeriveAddressesWithPassphrase(t *testing.T) {
	seed := bip39.NewSeed(testMnemonic, "TREZOR")

	addresses, err := DeriveAddresses(seed, 1)
	if err != nil {
		t.Fatalf("DeriveAddresses failed: %v", err)
	}

	// With passphrase, addresses should be different
	if len(addresses) == 0 {
		t.Error("Expected addresses to be generated")
	}

	// The first BIP44 address with "TREZOR" passphrase should be different
	addressMap := make(map[string]string)
	for _, addr := range addresses {
		addressMap[addr.Path] = addr.Address
	}

	// Should NOT match the address without passphrase
	if addr, exists := addressMap["m/44'/0'/0'/0/0"]; exists {
		if addr == "1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA" {
			t.Error("Address should be different with passphrase")
		}
	}
}
