package auth

import (
	"context"
	"testing"
	"time"
)

func TestAPIKey_IsIPAllowed(t *testing.T) {
	tests := []struct {
		name       string
		allowedIPs []string
		clientIP   string
		want       bool
	}{
		{
			name:       "no restrictions - any IP allowed",
			allowedIPs: nil,
			clientIP:   "192.168.1.100",
			want:       true,
		},
		{
			name:       "empty restrictions - any IP allowed",
			allowedIPs: []string{},
			clientIP:   "10.0.0.5",
			want:       true,
		},
		{
			name:       "single IP match",
			allowedIPs: []string{"192.168.1.100"},
			clientIP:   "192.168.1.100",
			want:       true,
		},
		{
			name:       "single IP no match",
			allowedIPs: []string{"192.168.1.100"},
			clientIP:   "192.168.1.101",
			want:       false,
		},
		{
			name:       "CIDR match",
			allowedIPs: []string{"192.168.1.0/24"},
			clientIP:   "192.168.1.55",
			want:       true,
		},
		{
			name:       "CIDR no match",
			allowedIPs: []string{"192.168.1.0/24"},
			clientIP:   "192.168.2.1",
			want:       false,
		},
		{
			name:       "multiple CIDRs - first matches",
			allowedIPs: []string{"10.0.0.0/8", "192.168.0.0/16"},
			clientIP:   "10.50.25.100",
			want:       true,
		},
		{
			name:       "multiple CIDRs - second matches",
			allowedIPs: []string{"10.0.0.0/8", "192.168.0.0/16"},
			clientIP:   "192.168.50.1",
			want:       true,
		},
		{
			name:       "multiple CIDRs - none match",
			allowedIPs: []string{"10.0.0.0/8", "192.168.0.0/16"},
			clientIP:   "172.16.0.1",
			want:       false,
		},
		{
			name:       "mixed IP and CIDR - IP matches",
			allowedIPs: []string{"10.0.0.0/8", "172.16.0.1"},
			clientIP:   "172.16.0.1",
			want:       true,
		},
		{
			name:       "mixed IP and CIDR - CIDR matches",
			allowedIPs: []string{"10.0.0.0/8", "172.16.0.1"},
			clientIP:   "10.1.2.3",
			want:       true,
		},
		{
			name:       "IPv6 CIDR",
			allowedIPs: []string{"2001:db8::/32"},
			clientIP:   "2001:db8:1234:5678::1",
			want:       true,
		},
		{
			name:       "IPv6 no match",
			allowedIPs: []string{"2001:db8::/32"},
			clientIP:   "2001:db9::1",
			want:       false,
		},
		{
			name:       "invalid client IP",
			allowedIPs: []string{"192.168.1.0/24"},
			clientIP:   "not-an-ip",
			want:       false,
		},
		{
			name:       "invalid CIDR in allowlist (fallback to IP parse)",
			allowedIPs: []string{"invalid/cidr", "192.168.1.100"},
			clientIP:   "192.168.1.100",
			want:       true,
		},
	}

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

func TestService_CreateWithAllowedIPs(t *testing.T) {
	svc := newTestService(t, "admin-key")

	t.Run("creates key with IP restrictions", func(t *testing.T) {
		resp, err := svc.Create(context.Background(), CreateKeyRequest{
			Name:       "test-ip-key",
			Scopes:     []Scope{ScopeProjectsRead},
			AllowedIPs: []string{"192.168.1.0/24", "10.0.0.1"},
			ExpiresIn:  24 * time.Hour,
			CreatedBy:  "test",
		})
		if err != nil {
			t.Fatalf("Create() error = %v", err)
		}

		if len(resp.Key.AllowedIPs) != 2 {
			t.Errorf("Key.AllowedIPs length = %d, want 2", len(resp.Key.AllowedIPs))
		}

		key, err := svc.Get(context.Background(), string(resp.Key.ID))
		if err != nil {
			t.Fatalf("Get() error = %v", err)
		}

		if len(key.AllowedIPs) != 2 {
			t.Errorf("Retrieved Key.AllowedIPs length = %d, want 2", len(key.AllowedIPs))
		}

		validatedKey, err := svc.Validate(context.Background(), resp.Secret)
		if err != nil {
			t.Fatalf("Validate() error = %v", err)
		}

		if len(validatedKey.AllowedIPs) != 2 {
			t.Errorf("Validated Key.AllowedIPs length = %d, want 2", len(validatedKey.AllowedIPs))
		}

		if !validatedKey.IsIPAllowed("192.168.1.50") {
			t.Error("IsIPAllowed should return true for IP in allowed CIDR")
		}
		if !validatedKey.IsIPAllowed("10.0.0.1") {
			t.Error("IsIPAllowed should return true for explicitly allowed IP")
		}
		if validatedKey.IsIPAllowed("172.16.0.1") {
			t.Error("IsIPAllowed should return false for IP not in allowed list")
		}
	})

	t.Run("creates key with no IP restrictions", func(t *testing.T) {
		resp, err := svc.Create(context.Background(), CreateKeyRequest{
			Name:      "test-no-ip-key",
			Scopes:    []Scope{ScopeProjectsRead},
			ExpiresIn: 24 * time.Hour,
			CreatedBy: "test",
		})
		if err != nil {
			t.Fatalf("Create() error = %v", err)
		}

		if len(resp.Key.AllowedIPs) != 0 {
			t.Errorf("Key.AllowedIPs should be empty, got %v", resp.Key.AllowedIPs)
		}

		validatedKey, err := svc.Validate(context.Background(), resp.Secret)
		if err != nil {
			t.Fatalf("Validate() error = %v", err)
		}

		if !validatedKey.IsIPAllowed("1.2.3.4") {
			t.Error("IsIPAllowed should return true when no restrictions set")
		}
	})
}
