// SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
// SPDX-License-Identifier: Apache-2.0

package registry_test

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/stacklok/toolhive/pkg/config"
	"github.com/stacklok/toolhive/pkg/registry"
)

func TestConfigurator_SetRegistryFromInput(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name           string
		input          string
		allowPrivateIP bool
		expectedType   string
		expectError    bool
		setupFunc      func(t *testing.T) string // Returns path to test file if needed
		cleanupFunc    func(path string)
	}{
		{
			name:           "set local registry file",
			allowPrivateIP: false,
			expectedType:   config.RegistryTypeFile,
			expectError:    false,
			setupFunc: func(t *testing.T) string {
				t.Helper()
				tmpFile := filepath.Join(t.TempDir(), "test-registry.json")
				content := []byte(`{
					"$schema": "https://example.com/schema.json",
					"version": "0.1",
					"meta": {"last_updated": "2025-01-01T00:00:00Z"},
					"data": {"servers": [{"name": "io.example.test"}]}
				}`)
				require.NoError(t, os.WriteFile(tmpFile, content, 0600))
				return tmpFile
			},
		},
		{
			name:           "invalid local file - missing",
			allowPrivateIP: false,
			expectedType:   config.RegistryTypeFile,
			expectError:    true,
			setupFunc: func(_ *testing.T) string {
				return "/tmp/non-existent-file-xyz123.json"
			},
		},
		{
			name:           "invalid local file - wrong structure",
			allowPrivateIP: false,
			expectedType:   config.RegistryTypeFile,
			expectError:    true,
			setupFunc: func(t *testing.T) string {
				t.Helper()
				tmpFile := filepath.Join(t.TempDir(), "invalid-registry.json")
				content := []byte(`{"invalid": "structure"}`)
				require.NoError(t, os.WriteFile(tmpFile, content, 0600))
				return tmpFile
			},
		},
	}

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

			// Create a test config provider
			tmpDir := t.TempDir()
			configPath := filepath.Join(tmpDir, "config.yaml")
			provider := config.NewPathProvider(configPath)
			service := registry.NewConfiguratorWithProvider(provider)

			// Setup test data if needed
			var input string
			if tt.setupFunc != nil {
				input = tt.setupFunc(t)
			} else {
				input = tt.input
			}

			// Call the service
			registryType, err := service.SetRegistryFromInput(input, tt.allowPrivateIP)

			// Check results
			if tt.expectError {
				assert.Error(t, err, "Expected an error")
				assert.Equal(t, tt.expectedType, registryType, "Registry type should be returned even on error")
			} else {
				assert.NoError(t, err, "Should not return error")
				assert.Equal(t, tt.expectedType, registryType, "Registry type should match")
			}
		})
	}
}

func TestConfigurator_UnsetRegistry(t *testing.T) {
	t.Parallel()

	// Create a test config provider with a registry set
	tmpDir := t.TempDir()
	configPath := filepath.Join(tmpDir, "config.yaml")
	tmpFile := filepath.Join(tmpDir, "test-registry.json")

	// Create a valid registry file
	content := []byte(`{
		"$schema": "https://example.com/schema.json",
		"version": "0.1",
		"meta": {"last_updated": "2025-01-01T00:00:00Z"},
		"data": {"servers": [{"name": "io.example.test"}]}
	}`)
	require.NoError(t, os.WriteFile(tmpFile, content, 0600))

	provider := config.NewPathProvider(configPath)
	service := registry.NewConfiguratorWithProvider(provider)

	// First, set a registry
	_, err := service.SetRegistryFromInput(tmpFile, false)
	require.NoError(t, err, "Should be able to set registry")

	// Verify it's set
	registryType, source := service.GetRegistryInfo()
	assert.Equal(t, config.RegistryTypeFile, registryType, "Registry type should be file")
	assert.NotEmpty(t, source, "Source should not be empty")

	// Now unset it
	err = service.UnsetRegistry()
	assert.NoError(t, err, "Should be able to unset registry")

	// Verify it's unset
	registryType, source = service.GetRegistryInfo()
	assert.Equal(t, config.RegistryTypeDefault, registryType, "Registry type should be default")
	assert.Empty(t, source, "Source should be empty")
}

func TestConfigurator_GetRegistryInfo(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name           string
		setupFunc      func(t *testing.T, service registry.Configurator)
		expectedType   string
		expectedSource string // Empty means we don't check it
	}{
		{
			name:           "default registry",
			setupFunc:      nil, // No setup, should be default
			expectedType:   config.RegistryTypeDefault,
			expectedSource: "",
		},
		{
			name: "local file registry",
			setupFunc: func(t *testing.T, service registry.Configurator) {
				t.Helper()
				tmpFile := filepath.Join(t.TempDir(), "test-registry.json")
				content := []byte(`{
					"$schema": "https://example.com/schema.json",
					"version": "0.1",
					"meta": {"last_updated": "2025-01-01T00:00:00Z"},
					"data": {"servers": [{"name": "io.example.test"}]}
				}`)
				require.NoError(t, os.WriteFile(tmpFile, content, 0600))
				_, err := service.SetRegistryFromInput(tmpFile, false)
				require.NoError(t, err)
			},
			expectedType: config.RegistryTypeFile,
		},
	}

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

			// Create a test config provider
			tmpDir := t.TempDir()
			configPath := filepath.Join(tmpDir, "config.yaml")
			provider := config.NewPathProvider(configPath)
			service := registry.NewConfiguratorWithProvider(provider)

			// Setup if needed
			if tt.setupFunc != nil {
				tt.setupFunc(t, service)
			}

			// Get registry info
			registryType, source := service.GetRegistryInfo()

			// Check results
			assert.Equal(t, tt.expectedType, registryType, "Registry type should match")
			if tt.expectedSource != "" {
				assert.Equal(t, tt.expectedSource, source, "Source should match")
			}
		})
	}
}
