package config

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

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

func TestLoadConfig(t *testing.T) {
	// Test loading non-existent config file
	config, err := LoadConfig("/non/existent/path")
	assert.Error(t, err)
	assert.Nil(t, config)

	// Test loading with default config (may fail if no config file exists)
	config, err = LoadConfig("")
	if err != nil {
		// If no config file is found, that's expected in test environment
		assert.Contains(t, err.Error(), "no configuration file found")
	} else {
		assert.NotNil(t, config)
		assert.Equal(t, "development", config.ActiveRegistry)
	}
}

func TestLoadConfigFromFile(t *testing.T) {
	// Create a temporary config file
	tmpDir := t.TempDir()
	configPath := filepath.Join(tmpDir, "registry.yaml")
	
	configContent := `registries:
  development:
    base_url: "git.raines.xyz"
    namespace: "debian"
    auth_required: true
  production:
    base_url: "docker.io"
    namespace: "debian"
    auth_required: false

active_registry: "development"

containers:
  bootc_base: "{registry}/{namespace}/debian-bootc:{version}"
  bootc_builder: "{registry}/{namespace}/bootc-image-builder:{tag}"

versions:
  debian:
    stable: "trixie"
    testing: "forky"
    unstable: "sid"
    12: "bookworm"
    13: "trixie"

defaults:
  debian_version: "trixie"
  image_types: ["qcow2"]
  output_dir: "./output"
  rootfs_type: "ext4"
  architecture: "amd64"

build:
  container_size_multiplier: 2
  min_rootfs_size_gb: 10
  default_kernel_options: ["rw", "console=tty0", "console=ttyS0"]

repositories:
  debian:
    main: "http://deb.debian.org/debian"
  debian_forge:
    base_url: "https://git.raines.xyz/api/packages/particle-os/debian"
    components: ["trixie", "main"]

cloud:
  aws:
    default_region: "us-east-1"
    bucket_template: "debian-bootc-{region}-{timestamp}"
`

	err := os.WriteFile(configPath, []byte(configContent), 0644)
	require.NoError(t, err)

	// Load the config
	config, err := LoadConfig(configPath)
	assert.NoError(t, err)
	assert.NotNil(t, config)

	// Test registry configuration
	assert.Equal(t, "development", config.ActiveRegistry)
	assert.Len(t, config.Registries, 2)
	
	devReg := config.Registries["development"]
	assert.Equal(t, "git.raines.xyz", devReg.BaseURL)
	assert.Equal(t, "debian", devReg.Namespace)
	assert.True(t, devReg.AuthRequired)
	
	prodReg := config.Registries["production"]
	assert.Equal(t, "docker.io", prodReg.BaseURL)
	assert.Equal(t, "debian", prodReg.Namespace)
	assert.False(t, prodReg.AuthRequired)

	// Test container templates
	assert.Equal(t, "{registry}/{namespace}/debian-bootc:{version}", config.Containers.BootcBase)
	assert.Equal(t, "{registry}/{namespace}/bootc-image-builder:{tag}", config.Containers.BootcBuilder)

	// Test version mappings
	assert.Equal(t, "trixie", config.Versions.Debian["stable"])
	assert.Equal(t, "forky", config.Versions.Debian["testing"])
	assert.Equal(t, "sid", config.Versions.Debian["unstable"])
	assert.Equal(t, "bookworm", config.Versions.Debian["12"])
	assert.Equal(t, "trixie", config.Versions.Debian["13"])

	// Test defaults
	assert.Equal(t, "trixie", config.Defaults.DebianVersion)
	assert.Equal(t, []string{"qcow2"}, config.Defaults.ImageTypes)
	assert.Equal(t, "./output", config.Defaults.OutputDir)
	assert.Equal(t, "ext4", config.Defaults.RootfsType)
	assert.Equal(t, "amd64", config.Defaults.Architecture)

	// Test build settings
	assert.Equal(t, 2, config.Build.ContainerSizeMultiplier)
	assert.Equal(t, 10, config.Build.MinRootfsSizeGB)
	assert.Equal(t, []string{"rw", "console=tty0", "console=ttyS0"}, config.Build.DefaultKernelOptions)

	// Test repositories
	assert.Len(t, config.Repositories.Debian, 1)
	
	debianRepo := config.Repositories.Debian["main"]
	assert.Equal(t, "http://deb.debian.org/debian", debianRepo)
	
	forgeRepo := config.Repositories.DebianForge
	assert.Equal(t, "https://git.raines.xyz/api/packages/particle-os/debian", forgeRepo.BaseURL)
	assert.Equal(t, []string{"trixie", "main"}, forgeRepo.Components)

	// Test cloud configuration
	assert.Equal(t, "us-east-1", config.Cloud.AWS.DefaultRegion)
	assert.Equal(t, "debian-bootc-{region}-{timestamp}", config.Cloud.AWS.BucketTemplate)
}

func TestConfigMethods(t *testing.T) {
	// Create a test config
	config := &Config{
		ActiveRegistry: "development",
		Registries: map[string]RegistryConfig{
			"development": {
				BaseURL:      "git.raines.xyz",
				Namespace:    "debian",
				AuthRequired: true,
			},
		},
		Containers: ContainerTemplates{
			BootcBase:   "{registry}/{namespace}/debian-bootc:{version}",
			BootcBuilder: "{registry}/{namespace}/bootc-image-builder:{tag}",
		},
		Versions: VersionMappings{
			Debian: map[string]string{
				"stable":   "trixie",
				"testing":  "forky",
				"unstable": "sid",
			},
		},
		Defaults: DefaultSettings{
			DebianVersion: "stable",
			ImageTypes:    []string{"qcow2"},
			OutputDir:     "./output",
			RootfsType:    "ext4",
			Architecture:  "amd64",
		},
		Build: BuildSettings{
			ContainerSizeMultiplier: 2,
			MinRootfsSizeGB:         10,
			DefaultKernelOptions:    []string{"rw", "console=tty0"},
		},
		Repositories: RepositoryConfig{
			Debian: map[string]string{
				"main": "http://deb.debian.org/debian",
			},
			DebianForge: struct {
				BaseURL    string   `yaml:"base_url"`
				Components []string `yaml:"components"`
			}{
				BaseURL:    "https://git.raines.xyz/api/packages/particle-os/debian",
				Components: []string{"trixie", "main"},
			},
		},
		Cloud: CloudConfig{
			AWS: struct {
				DefaultRegion   string `yaml:"default_region"`
				BucketTemplate  string `yaml:"bucket_template"`
			}{
				DefaultRegion:  "us-east-1",
				BucketTemplate: "debian-bootc-{region}-{timestamp}",
			},
		},
	}

	// Test GetActiveRegistry
	activeReg, err := config.GetActiveRegistry()
	assert.NoError(t, err)
	assert.Equal(t, "git.raines.xyz", activeReg.BaseURL)
	
	// Test GetDebianVersion
	version, err := config.GetDebianVersion("stable")
	assert.NoError(t, err)
	assert.Equal(t, "trixie", version)
	
	// Test GetDefaultDebianVersion
	defaultVersion, err := config.GetDefaultDebianVersion()
	assert.NoError(t, err)
	assert.Equal(t, "trixie", defaultVersion)
	
	// Test GetDefaultKernelOptions
	kernelOptions := config.GetDefaultKernelOptions()
	assert.Equal(t, []string{"rw", "console=tty0"}, kernelOptions)
	
	// Test GetContainerSizeMultiplier
	multiplier := config.GetContainerSizeMultiplier()
	assert.Equal(t, 2, multiplier)
	
	// Test GetMinRootfsSizeGB
	minSize := config.GetMinRootfsSizeGB()
	assert.Equal(t, 10, minSize)
	
	// Test GetDebianForgeRepository
	baseURL, components := config.GetDebianForgeRepository()
	assert.Equal(t, "https://git.raines.xyz/api/packages/particle-os/debian", baseURL)
	assert.Equal(t, []string{"trixie", "main"}, components)
}

func TestConfigWithInvalidYAML(t *testing.T) {
	// Create a temporary config file with invalid YAML
	tmpDir := t.TempDir()
	configPath := filepath.Join(tmpDir, "invalid.yaml")
	
	invalidContent := `registries:
  development:
    base_url: "git.raines.xyz"
    namespace: "debian"
    auth_required: true
  production:
    base_url: "docker.io"
    namespace: "debian"
    auth_required: false

active_registry: "development"

containers:
  bootc_base: "{registry}/{namespace}/debian-bootc:{version}"
  bootc_builder: "{registry}/{namespace}/bootc-image-builder:{tag}"

versions:
  debian:
    stable: "trixie"
    testing: "forky"
    unstable: "sid"
    12: "bookworm"
    13: "trixie"

defaults:
  debian_version: "trixie"
  image_types: ["qcow2"]
  output_dir: "./output"
  rootfs_type: "ext4"
  architecture: "amd64"

build:
  container_size_multiplier: 2
  min_rootfs_size_gb: 10
  default_kernel_options: ["rw", "console=tty0", "console=ttyS0"]

repositories:
  debian:
    main: "http://deb.debian.org/debian"
  debian_forge:
    base_url: "https://git.raines.xyz/api/packages/particle-os/debian"
    components: ["trixie", "main"]

cloud:
  aws:
    default_region: "us-east-1"
    bucket_template: "debian-bootc-{region}-{timestamp}"
`

	err := os.WriteFile(configPath, []byte(invalidContent), 0644)
	require.NoError(t, err)

	// Load the config
	config, err := LoadConfig(configPath)
	assert.NoError(t, err)
	assert.NotNil(t, config)
}

func TestConfigWithMissingFields(t *testing.T) {
	// Create a minimal config file
	tmpDir := t.TempDir()
	configPath := filepath.Join(tmpDir, "minimal.yaml")
	
	minimalContent := `registries:
  development:
    base_url: "git.raines.xyz"
    namespace: "debian"
    auth_required: true

active_registry: "development"

containers:
  bootc_base: "{registry}/{namespace}/debian-bootc:{version}"
  bootc_builder: "{registry}/{namespace}/bootc-image-builder:{tag}"

versions:
  debian:
    stable: "trixie"
    testing: "forky"
    unstable: "sid"
    12: "bookworm"
    13: "trixie"

defaults:
  debian_version: "trixie"
  image_types: ["qcow2"]
  output_dir: "./output"
  rootfs_type: "ext4"
  architecture: "amd64"

build:
  container_size_multiplier: 2
  min_rootfs_size_gb: 10
  default_kernel_options: ["rw", "console=tty0", "console=ttyS0"]

repositories:
  debian:
    main: "http://deb.debian.org/debian"
  debian_forge:
    base_url: "https://git.raines.xyz/api/packages/particle-os/debian"
    components: ["trixie", "main"]

cloud:
  aws:
    default_region: "us-east-1"
    bucket_template: "debian-bootc-{region}-{timestamp}"
`

	err := os.WriteFile(configPath, []byte(minimalContent), 0644)
	require.NoError(t, err)

	// Load the config
	config, err := LoadConfig(configPath)
	assert.NoError(t, err)
	assert.NotNil(t, config)

	// Test that missing fields have default values
	assert.Equal(t, "development", config.ActiveRegistry)
	assert.Len(t, config.Registries, 1)
	assert.Equal(t, "trixie", config.Versions.Debian["stable"])
	assert.Equal(t, "trixie", config.Defaults.DebianVersion)
	assert.Equal(t, []string{"qcow2"}, config.Defaults.ImageTypes)
	assert.Equal(t, "./output", config.Defaults.OutputDir)
	assert.Equal(t, "ext4", config.Defaults.RootfsType)
	assert.Equal(t, "amd64", config.Defaults.Architecture)
	assert.Equal(t, 2, config.Build.ContainerSizeMultiplier)
	assert.Equal(t, 10, config.Build.MinRootfsSizeGB)
	assert.Equal(t, []string{"rw", "console=tty0", "console=ttyS0"}, config.Build.DefaultKernelOptions)
	assert.Len(t, config.Repositories.Debian, 1)
	assert.Equal(t, "us-east-1", config.Cloud.AWS.DefaultRegion)
}
