package services

import (
	"context"
	"fmt"
	"testing"
	"time"

	"go.uber.org/zap"
)

func TestNewCDNService(t *testing.T) {
	config := CDNConfig{
		Provider: CDNProviderCloudFront,
		BaseURL:  "https://d1234567890.cloudfront.net",
		Enabled:  true,
		Logger:   zap.NewNop(),
	}

	service := NewCDNService(config)

	if service == nil {
		t.Error("NewCDNService() returned nil")
	}
	if service.logger == nil {
		t.Error("NewCDNService() returned service with nil logger")
	}
	if service.config.Provider != CDNProviderCloudFront {
		t.Errorf("NewCDNService() provider = %v, want %v", service.config.Provider, CDNProviderCloudFront)
	}
}

func TestCDNService_GetURL(t *testing.T) {
	tests := []struct {
		name     string
		config   CDNConfig
		path     string
		expected string
	}{
		{
			name: "CloudFront enabled",
			config: CDNConfig{
				Provider: CDNProviderCloudFront,
				BaseURL:  "https://d1234567890.cloudfront.net",
				Enabled:  true,
				Logger:   zap.NewNop(),
			},
			path:     "/audio/track123.mp3",
			expected: "https://d1234567890.cloudfront.net/audio/track123.mp3",
		},
		{
			name: "CDN disabled",
			config: CDNConfig{
				Provider: CDNProviderCloudFront,
				BaseURL:  "https://d1234567890.cloudfront.net",
				Enabled:  false,
				Logger:   zap.NewNop(),
			},
			path:     "/audio/track123.mp3",
			expected: "/audio/track123.mp3",
		},
		{
			name: "None provider",
			config: CDNConfig{
				Provider: CDNProviderNone,
				BaseURL:  "https://d1234567890.cloudfront.net",
				Enabled:  true,
				Logger:   zap.NewNop(),
			},
			path:     "/audio/track123.mp3",
			expected: "/audio/track123.mp3",
		},
		{
			name: "Path without leading slash",
			config: CDNConfig{
				Provider: CDNProviderCloudFront,
				BaseURL:  "https://d1234567890.cloudfront.net",
				Enabled:  true,
				Logger:   zap.NewNop(),
			},
			path:     "audio/track123.mp3",
			expected: "https://d1234567890.cloudfront.net/audio/track123.mp3",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			service := NewCDNService(tt.config)
			result := service.GetURL(tt.path)
			if result != tt.expected {
				t.Errorf("GetURL(%s) = %s, want %s", tt.path, result, tt.expected)
			}
		})
	}
}

func TestCDNService_GetAssetURL(t *testing.T) {
	config := CDNConfig{
		Provider: CDNProviderCloudFront,
		BaseURL:  "https://d1234567890.cloudfront.net",
		Enabled:  true,
		Logger:   zap.NewNop(),
	}

	service := NewCDNService(config)
	url := service.GetAssetURL("js", "app.js")

	expected := "https://d1234567890.cloudfront.net/assets/js/app.js"
	if url != expected {
		t.Errorf("GetAssetURL() = %s, want %s", url, expected)
	}
}

func TestCDNService_GetAudioURL(t *testing.T) {
	config := CDNConfig{
		Provider: CDNProviderCloudFront,
		BaseURL:  "https://d1234567890.cloudfront.net",
		Enabled:  true,
		Logger:   zap.NewNop(),
	}

	service := NewCDNService(config)
	url := service.GetAudioURL("track-123", "audio.mp3")

	expected := "https://d1234567890.cloudfront.net/audio/track-123/audio.mp3"
	if url != expected {
		t.Errorf("GetAudioURL() = %s, want %s", url, expected)
	}
}

func TestCDNService_GetHLSURL(t *testing.T) {
	config := CDNConfig{
		Provider: CDNProviderCloudFront,
		BaseURL:  "https://d1234567890.cloudfront.net",
		Enabled:  true,
		Logger:   zap.NewNop(),
	}

	service := NewCDNService(config)
	url := service.GetHLSURL("track-123", "master.m3u8")

	expected := "https://d1234567890.cloudfront.net/hls/track-123/master.m3u8"
	if url != expected {
		t.Errorf("GetHLSURL() = %s, want %s", url, expected)
	}
}

func TestCDNService_GetImageURL(t *testing.T) {
	config := CDNConfig{
		Provider: CDNProviderCloudFront,
		BaseURL:  "https://d1234567890.cloudfront.net",
		Enabled:  true,
		Logger:   zap.NewNop(),
	}

	service := NewCDNService(config)
	url := service.GetImageURL("avatars", "user-123.jpg")

	expected := "https://d1234567890.cloudfront.net/images/avatars/user-123.jpg"
	if url != expected {
		t.Errorf("GetImageURL() = %s, want %s", url, expected)
	}
}

func TestCDNService_IsEnabled(t *testing.T) {
	tests := []struct {
		name     string
		config   CDNConfig
		expected bool
	}{
		{
			name: "enabled CloudFront",
			config: CDNConfig{
				Provider: CDNProviderCloudFront,
				Enabled:  true,
				Logger:   zap.NewNop(),
			},
			expected: true,
		},
		{
			name: "disabled",
			config: CDNConfig{
				Provider: CDNProviderCloudFront,
				Enabled:  false,
				Logger:   zap.NewNop(),
			},
			expected: false,
		},
		{
			name: "none provider",
			config: CDNConfig{
				Provider: CDNProviderNone,
				Enabled:  true,
				Logger:   zap.NewNop(),
			},
			expected: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			service := NewCDNService(tt.config)
			result := service.IsEnabled()
			if result != tt.expected {
				t.Errorf("IsEnabled() = %v, want %v", result, tt.expected)
			}
		})
	}
}

func TestCDNService_GetProvider(t *testing.T) {
	config := CDNConfig{
		Provider: CDNProviderCloudflare,
		Enabled:  true,
		Logger:   zap.NewNop(),
	}

	service := NewCDNService(config)
	provider := service.GetProvider()

	if provider != CDNProviderCloudflare {
		t.Errorf("GetProvider() = %v, want %v", provider, CDNProviderCloudflare)
	}
}

func TestCDNService_GetBaseURL(t *testing.T) {
	expectedURL := "https://d1234567890.cloudfront.net"
	config := CDNConfig{
		Provider: CDNProviderCloudFront,
		BaseURL:  expectedURL,
		Enabled:  true,
		Logger:   zap.NewNop(),
	}

	service := NewCDNService(config)
	baseURL := service.GetBaseURL()

	if baseURL != expectedURL {
		t.Errorf("GetBaseURL() = %s, want %s", baseURL, expectedURL)
	}
}

func TestCDNService_GetCacheHeaders(t *testing.T) {
	tests := []struct {
		name           string
		config         CDNConfig
		expectedHeader string
	}{
		{
			name: "CloudFront enabled",
			config: CDNConfig{
				Provider: CDNProviderCloudFront,
				Enabled:  true,
				Logger:   zap.NewNop(),
			},
			expectedHeader: "public, max-age=31536000, immutable",
		},
		{
			name: "Cloudflare enabled",
			config: CDNConfig{
				Provider: CDNProviderCloudflare,
				Enabled:  true,
				Logger:   zap.NewNop(),
			},
			expectedHeader: "public, max-age=31536000, immutable",
		},
		{
			name: "CDN disabled",
			config: CDNConfig{
				Provider: CDNProviderCloudFront,
				Enabled:  false,
				Logger:   zap.NewNop(),
			},
			expectedHeader: "no-cache",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			service := NewCDNService(tt.config)
			headers := service.GetCacheHeaders()

			cacheControl := headers["Cache-Control"]
			if cacheControl != tt.expectedHeader {
				t.Errorf("GetCacheHeaders() Cache-Control = %s, want %s", cacheControl, tt.expectedHeader)
			}
		})
	}
}

func TestCDNService_InvalidateCache(t *testing.T) {
	config := CDNConfig{
		Provider: CDNProviderGeneric,
		BaseURL:  "https://cdn.example.com",
		Enabled:  true,
		Logger:   zap.NewNop(),
	}

	service := NewCDNService(config)
	ctx := context.Background()

	paths := []string{"/audio/track1.mp3", "/audio/track2.mp3"}
	err := service.InvalidateCache(ctx, paths)
	if err != nil {
		t.Errorf("InvalidateCache() error = %v", err)
	}
}

func TestCDNService_BatchInvalidate(t *testing.T) {
	config := CDNConfig{
		Provider: CDNProviderGeneric,
		BaseURL:  "https://cdn.example.com",
		Enabled:  true,
		Logger:   zap.NewNop(),
	}

	service := NewCDNService(config)
	ctx := context.Background()

	paths := make([]string, 25)
	for i := 0; i < 25; i++ {
		paths[i] = fmt.Sprintf("/audio/track%d.mp3", i)
	}

	err := service.BatchInvalidate(ctx, paths, 10)
	if err != nil {
		t.Errorf("BatchInvalidate() error = %v", err)
	}
}

func TestCDNService_GenerateSignedURL(t *testing.T) {
	config := CDNConfig{
		Provider: CDNProviderCloudFront,
		BaseURL:  "https://d1234567890.cloudfront.net",
		Enabled:  true,
		Logger:   zap.NewNop(),
	}

	service := NewCDNService(config)
	url, err := service.GenerateSignedURL("/audio/track123.mp3", time.Hour)
	if err != nil {
		t.Errorf("GenerateSignedURL() error = %v", err)
	}
	if url == "" {
		t.Error("GenerateSignedURL() returned empty URL")
	}
}

// Note: Full integration tests would require:
// 1. Real CDN provider credentials
// 2. Actual CDN distribution/zone
// 3. Verification of cache invalidation
// 4. Testing of signed URL generation
//
// Example integration test structure:
// func TestCDNService_InvalidateCache_Integration(t *testing.T) {
//     // Skip if CDN not configured
//     if os.Getenv("CDN_ENABLED") != "true" {
//         t.Skip("CDN not configured")
//     }
//
//     config := CDNConfig{
//         Provider:      CDNProviderCloudFront,
//         BaseURL:       os.Getenv("CDN_BASE_URL"),
//         DistributionID: os.Getenv("CDN_DISTRIBUTION_ID"),
//         APIKey:        os.Getenv("CDN_API_KEY"),
//         Enabled:       true,
//         Logger:        zap.NewNop(),
//     }
//
//     service := NewCDNService(config)
//     ctx := context.Background()
//
//     paths := []string{"/test/path1.mp3", "/test/path2.mp3"}
//     err := service.InvalidateCache(ctx, paths)
//     if err != nil {
//         t.Fatalf("InvalidateCache() error = %v", err)
//     }
//
//     // Verify invalidation was successful (check CDN API)
// }
