package auth

import (
	"testing"
	"time"
)

func TestParseExpiration(t *testing.T) {
	tests := []struct {
		name    string
		input   string
		want    time.Duration
		wantErr bool
	}{
		{"30d", "30d", Expiration30Days, false},
		{"30", "30", Expiration30Days, false},
		{"60d", "60d", Expiration60Days, false},
		{"60", "60", Expiration60Days, false},
		{"90d", "90d", Expiration90Days, false},
		{"90", "90", Expiration90Days, false},
		{"1y", "1y", Expiration1Year, false},
		{"1year", "1year", Expiration1Year, false},
		{"365d", "365d", Expiration1Year, false},
		{"never", "never", ExpirationNoLimit, false},
		{"none", "none", ExpirationNoLimit, false},
		{"empty", "", ExpirationNoLimit, false},
		{"case insensitive", "30D", Expiration30Days, false},
		{"invalid", "invalid", 0, true},
		{"7d", "7d", 0, true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := ParseExpiration(tt.input)
			if (err != nil) != tt.wantErr {
				t.Errorf("ParseExpiration(%q) error = %v, wantErr %v", tt.input, err, tt.wantErr)
				return
			}
			if got != tt.want {
				t.Errorf("ParseExpiration(%q) = %v, want %v", tt.input, got, tt.want)
			}
		})
	}
}

func TestExpiresAt(t *testing.T) {
	t.Run("returns nil for zero duration", func(t *testing.T) {
		got := ExpiresAt(0)
		if got != nil {
			t.Errorf("ExpiresAt(0) = %v, want nil", got)
		}
	})

	t.Run("returns future time for positive duration", func(t *testing.T) {
		before := time.Now()
		got := ExpiresAt(24 * time.Hour)
		after := time.Now()

		if got == nil {
			t.Fatal("ExpiresAt(24h) returned nil")
		}

		expectedMin := before.Add(24 * time.Hour)
		expectedMax := after.Add(24 * time.Hour)

		if got.Before(expectedMin) || got.After(expectedMax) {
			t.Errorf("ExpiresAt(24h) = %v, want between %v and %v", *got, expectedMin, expectedMax)
		}
	})
}

func TestGenerateKey(t *testing.T) {
	t.Run("generates unique keys", func(t *testing.T) {
		key1, id1, err := GenerateKey()
		if err != nil {
			t.Fatalf("GenerateKey() error = %v", err)
		}

		key2, id2, err := GenerateKey()
		if err != nil {
			t.Fatalf("GenerateKey() error = %v", err)
		}

		if key1 == key2 {
			t.Error("Generated keys should be unique")
		}

		if id1 == id2 {
			t.Error("Generated identifiers should be unique")
		}
	})

	t.Run("key has correct format", func(t *testing.T) {
		key, id, err := GenerateKey()
		if err != nil {
			t.Fatalf("GenerateKey() error = %v", err)
		}

		if !ValidateKeyFormat(key) {
			t.Errorf("Generated key %q has invalid format", key)
		}

		if len(id) != KeyIdentifierLength {
			t.Errorf("Identifier length = %d, want %d", len(id), KeyIdentifierLength)
		}
	})

	t.Run("key contains prefix and identifier", func(t *testing.T) {
		key, id, err := GenerateKey()
		if err != nil {
			t.Fatalf("GenerateKey() error = %v", err)
		}

		expectedPrefix := KeyPrefix + id + "_"
		if key[:len(expectedPrefix)] != expectedPrefix {
			t.Errorf("Key %q should start with %q", key, expectedPrefix)
		}
	})
}

func TestHashKey(t *testing.T) {
	t.Run("produces consistent hash", func(t *testing.T) {
		key := "rdev_sk_abc12345_0123456789abcdef0123456789abcdef"
		hash1 := HashKey(key)
		hash2 := HashKey(key)

		if hash1 != hash2 {
			t.Error("Same key should produce same hash")
		}
	})

	t.Run("different keys produce different hashes", func(t *testing.T) {
		hash1 := HashKey("key1")
		hash2 := HashKey("key2")

		if hash1 == hash2 {
			t.Error("Different keys should produce different hashes")
		}
	})

	t.Run("hash is hex encoded", func(t *testing.T) {
		hash := HashKey("test")
		// SHA-256 produces 32 bytes = 64 hex characters
		if len(hash) != 64 {
			t.Errorf("Hash length = %d, want 64", len(hash))
		}

		for _, c := range hash {
			if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) {
				t.Errorf("Hash contains non-hex character: %c", c)
			}
		}
	})
}

func TestValidateKeyFormat(t *testing.T) {
	tests := []struct {
		name string
		key  string
		want bool
	}{
		{"valid key", "rdev_sk_abc12345_0123456789abcdef0123456789abcdef", true},
		{"missing prefix", "abc12345_0123456789abcdef0123456789abcdef", false},
		{"wrong prefix", "api_sk_abc12345_0123456789abcdef0123456789abcdef", false},
		{"short identifier", "rdev_sk_abc1234_0123456789abcdef0123456789abcdef", false},
		{"long identifier", "rdev_sk_abc123456_0123456789abcdef0123456789abcdef", false},
		{"short random", "rdev_sk_abc12345_0123456789abcdef", false},
		{"long random", "rdev_sk_abc12345_0123456789abcdef0123456789abcdef00", false},
		{"missing underscore", "rdev_sk_abc123450123456789abcdef0123456789abcdef", false},
		{"extra underscore", "rdev_sk_abc12345_0123_456789abcdef0123456789abcdef", false},
		{"empty", "", false},
		{"only prefix", "rdev_sk_", false},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := ValidateKeyFormat(tt.key); got != tt.want {
				t.Errorf("ValidateKeyFormat(%q) = %v, want %v", tt.key, got, tt.want)
			}
		})
	}
}

func TestExtractPrefix(t *testing.T) {
	tests := []struct {
		name string
		key  string
		want string
	}{
		{"valid key", "rdev_sk_abc12345_0123456789abcdef0123456789abcdef", "abc12345"},
		{"missing prefix", "abc12345_random", ""},
		{"only rdev_sk_", "rdev_sk_", ""},
		{"empty", "", ""},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := ExtractPrefix(tt.key); got != tt.want {
				t.Errorf("ExtractPrefix(%q) = %q, want %q", tt.key, got, tt.want)
			}
		})
	}
}
