package storage

import (
	"strings"
	"testing"

	"github.com/tidbcloud/observability/vmbackupmanager/pkg/config"
)

func TestParseStoragePath(t *testing.T) {
	tests := []struct {
		name     string
		path     string
		expected StorageInfo
	}{
		{
			name: "S3 storage with path",
			path: "s3://bucket/path/to/backup",
			expected: StorageInfo{
				Type:     StorageTypeS3,
				Bucket:   "bucket",
				Prefix:   "path/to/backup/",
				FullPath: "s3://bucket/path/to/backup/",
			},
		},
		{
			name: "S3 storage with path with trailing slash",
			path: "s3://bucket/path/to/backup/",
			expected: StorageInfo{
				Type:     StorageTypeS3,
				Bucket:   "bucket",
				Prefix:   "path/to/backup/",
				FullPath: "s3://bucket/path/to/backup/",
			},
		},
		{
			name: "S3 storage without path",
			path: "s3://bucket",
			expected: StorageInfo{
				Type:     StorageTypeS3,
				Bucket:   "bucket",
				Prefix:   "",
				FullPath: "s3://bucket",
			},
		},
		{
			name: "GCS storage with path",
			path: "gs://bucket/path/to/backup",
			expected: StorageInfo{
				Type:     StorageTypeGCS,
				Bucket:   "bucket",
				Prefix:   "path/to/backup/",
				FullPath: "gs://bucket/path/to/backup/",
			},
		},
		{
			name: "Azure Blob storage with path",
			path: "azblob://container/path/to/backup",
			expected: StorageInfo{
				Type:     StorageTypeAzure,
				Bucket:   "container",
				Prefix:   "path/to/backup/",
				FullPath: "azblob://container/path/to/backup/",
			},
		},
		{
			name: "File system storage with path",
			path: "fs:///local/path/to/backup",
			expected: StorageInfo{
				Type:     StorageTypeFS,
				Bucket:   "",
				Prefix:   "/local/path/to/backup",
				FullPath: "fs:///local/path/to/backup",
			},
		},
		{
			name: "File system storage with trailing slash",
			path: "fs:///local/path/to/backup/",
			expected: StorageInfo{
				Type:     StorageTypeFS,
				Bucket:   "",
				Prefix:   "/local/path/to/backup/",
				FullPath: "fs:///local/path/to/backup/",
			},
		},
		{
			name: "Invalid storage path format",
			path: "invalid-format",
			expected: StorageInfo{
				Type:     "",
				Bucket:   "",
				Prefix:   "",
				FullPath: "invalid-format",
			},
		},
		{
			name: "Unknown storage type",
			path: "unknown://bucket/path",
			expected: StorageInfo{
				Type:     "",
				Bucket:   "",
				Prefix:   "",
				FullPath: "unknown://bucket/path",
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := ParseStoragePath(tt.path)

			if result.Type != tt.expected.Type {
				t.Errorf("Type = %v, expected %v", result.Type, tt.expected.Type)
			}

			if result.Bucket != tt.expected.Bucket {
				t.Errorf("Bucket = %v, expected %v", result.Bucket, tt.expected.Bucket)
			}

			if result.Prefix != tt.expected.Prefix {
				t.Errorf("Prefix = %v, expected %v", result.Prefix, tt.expected.Prefix)
			}

			if result.FullPath != tt.expected.FullPath {
				t.Errorf("FullPath = %v, expected %v", result.FullPath, tt.expected.FullPath)
			}
		})
	}
}

// Test NewStorage function with different storage types
func TestNewStorage(t *testing.T) {
	tests := []struct {
		name          string
		dst           string
		expectType    string
		expectError   bool
		errorContains string
	}{
		{
			name:        "File system storage",
			dst:         "fs:///local/path",
			expectType:  "*storage.FSStorage",
			expectError: false,
		},
		{
			name:          "Unsupported storage type",
			dst:           "unsupported://bucket/path",
			expectType:    "",
			expectError:   true,
			errorContains: "unsupported storage type",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			cfg := &config.Config{
				Destination: tt.dst,
			}
			storage, err := NewStorage(cfg)

			// Check error expectations
			if (err != nil) != tt.expectError {
				t.Errorf("NewStorage() error = %v, expectError %v", err, tt.expectError)
				return
			}

			if err != nil && tt.errorContains != "" {
				if !contains(err.Error(), tt.errorContains) {
					t.Errorf("Error message '%v' does not contain '%v'", err.Error(), tt.errorContains)
				}
				return
			}

			if !tt.expectError {
				// Check storage type
				actualType := toString(storage)
				if actualType != tt.expectType {
					t.Errorf("Storage type = %v, expected %v", actualType, tt.expectType)
				}
			}
		})
	}
}

// Helper function to check if a string contains another string
func contains(s, substr string) bool {
	return s != "" && substr != "" && s != substr && strings.Contains(s, substr)
}

// Helper function to get the type as a string
func toString(v interface{}) string {
	if v == nil {
		return ""
	}
	return typeName(v)
}

// Helper function to get the type name
func typeName(v interface{}) string {
	switch v.(type) {
	case *FSStorage:
		return "*storage.FSStorage"
	default:
		return ""
	}
}
