package services

import (
	"testing"
	"time"

	"go.uber.org/zap"
)

func TestNewS3StorageService(t *testing.T) {
	tests := []struct {
		name    string
		cfg     S3Config
		wantErr bool
	}{
		{
			name: "valid config with bucket",
			cfg: S3Config{
				Bucket: "test-bucket",
				Region: "us-east-1",
				Logger: zap.NewNop(),
			},
			wantErr: false,
		},
		{
			name: "missing bucket",
			cfg: S3Config{
				Region: "us-east-1",
				Logger: zap.NewNop(),
			},
			wantErr: true,
		},
		{
			name: "default region",
			cfg: S3Config{
				Bucket: "test-bucket",
				Logger: zap.NewNop(),
			},
			wantErr: false,
		},
		{
			name: "with custom endpoint",
			cfg: S3Config{
				Bucket:   "test-bucket",
				Region:   "us-east-1",
				Endpoint: "http://localhost:9000",
				Logger:   zap.NewNop(),
			},
			wantErr: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// Note: Ces tests ne peuvent pas réellement se connecter à S3 sans credentials
			// Ils testent principalement la validation de configuration
			// Pour des tests d'intégration réels, il faudrait utiliser un mock ou un service local comme MinIO
			service, err := NewS3StorageService(tt.cfg)
			if (err != nil) != tt.wantErr {
				t.Errorf("NewS3StorageService() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !tt.wantErr && service == nil {
				t.Error("NewS3StorageService() returned nil service without error")
			}
		})
	}
}

func TestS3StorageService_GetPublicURL(t *testing.T) {
	tests := []struct {
		name     string
		service  *S3StorageService
		key      string
		expected string
	}{
		{
			name: "AWS S3 standard URL",
			service: &S3StorageService{
				bucket:   "test-bucket",
				region:   "us-east-1",
				endpoint: "",
			},
			key:      "tracks/user123/track456/file.mp3",
			expected: "https://test-bucket.s3.us-east-1.amazonaws.com/tracks/user123/track456/file.mp3",
		},
		{
			name: "MinIO custom endpoint URL",
			service: &S3StorageService{
				bucket:   "test-bucket",
				region:   "us-east-1",
				endpoint: "http://localhost:9000",
			},
			key:      "tracks/user123/track456/file.mp3",
			expected: "http://localhost:9000/test-bucket/tracks/user123/track456/file.mp3",
		},
	}

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

func TestS3Config_Defaults(t *testing.T) {
	cfg := S3Config{
		Bucket: "test-bucket",
		Logger: zap.NewNop(),
	}

	service, err := NewS3StorageService(cfg)
	if err == nil {
		// Si le service est créé, vérifier les valeurs par défaut
		if service.region != "us-east-1" {
			t.Errorf("Expected default region 'us-east-1', got %s", service.region)
		}
		if service.urlExpiry != time.Hour {
			t.Errorf("Expected default URL expiry 1h, got %v", service.urlExpiry)
		}
	}
	// Note: Le service peut échouer si le bucket n'existe pas, ce qui est normal
	_ = err
}

// TestS3StorageService_InterfaceCompliance vérifie que S3StorageService implémente bien l'interface S3Service
func TestS3StorageService_InterfaceCompliance(t *testing.T) {
	var _ S3Service = (*S3StorageService)(nil)
}

// Note: Les tests d'intégration réels nécessiteraient:
// 1. Un service S3 local (MinIO) ou des credentials AWS de test
// 2. Des mocks pour le client S3
// 3. Un contexte de test avec timeout
//
// Exemple de test d'intégration (à implémenter avec MinIO):
// func TestS3StorageService_UploadFile_Integration(t *testing.T) {
//     cfg := S3Config{
//         Bucket:   "test-bucket",
//         Region:   "us-east-1",
//         Endpoint: "http://localhost:9000", // MinIO
//         AccessKey: "minioadmin",
//         SecretKey: "minioadmin",
//         Logger: zap.NewNop(),
//     }
//     service, err := NewS3StorageService(cfg)
//     if err != nil {
//         t.Skip("S3 service not available for integration test")
//         return
//     }
//
//     ctx := context.Background()
//     testData := []byte("test file content")
//     key := "test/key.txt"
//
//     url, err := service.UploadFile(ctx, testData, key, "text/plain")
//     if err != nil {
//         t.Fatalf("UploadFile() error = %v", err)
//     }
//     if url == "" {
//         t.Error("UploadFile() returned empty URL")
//     }
//
//     // Cleanup
//     defer service.DeleteFile(ctx, key)
// }
