package domain

import "testing"

func TestIsValidComponentType(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		expected bool
	}{
		{"service", "service", true},
		{"worker", "worker", true},
		{"app-astro", "app-astro", true},
		{"app-react", "app-react", true},
		{"app-nextjs", "app-nextjs", true},
		{"cli", "cli", true},
		{"postgres", "postgres", true},
		{"redis", "redis", true},
		{"invalid", "invalid", false},
		{"empty", "", false},
		{"uppercase", "SERVICE", false},
		{"partial", "serv", false},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			result := IsValidComponentType(tc.input)
			if result != tc.expected {
				t.Errorf("IsValidComponentType(%q) = %v, want %v", tc.input, result, tc.expected)
			}
		})
	}
}

func TestComponentType_DestDir(t *testing.T) {
	tests := []struct {
		name          string
		componentType ComponentType
		expected      string
	}{
		{"service", ComponentTypeService, "services"},
		{"worker", ComponentTypeWorker, "workers"},
		{"app-astro", ComponentTypeAppAstro, "apps"},
		{"app-react", ComponentTypeAppReact, "apps"},
		{"app-nextjs", ComponentTypeAppNextJS, "apps"},
		{"cli", ComponentTypeCLI, "cli"},
		{"unknown", ComponentType("unknown"), ""},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			result := tc.componentType.DestDir()
			if result != tc.expected {
				t.Errorf("%s.DestDir() = %q, want %q", tc.componentType, result, tc.expected)
			}
		})
	}
}

func TestComponentType_StartingPort(t *testing.T) {
	tests := []struct {
		name          string
		componentType ComponentType
		expected      int
	}{
		{"service", ComponentTypeService, 8001},
		{"worker", ComponentTypeWorker, 0},
		{"app-astro", ComponentTypeAppAstro, 3001},
		{"app-react", ComponentTypeAppReact, 3001},
		{"app-nextjs", ComponentTypeAppNextJS, 3001},
		{"cli", ComponentTypeCLI, 0},
		{"unknown", ComponentType("unknown"), 0},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			result := tc.componentType.StartingPort()
			if result != tc.expected {
				t.Errorf("%s.StartingPort() = %d, want %d", tc.componentType, result, tc.expected)
			}
		})
	}
}

func TestComponentType_NeedsPort(t *testing.T) {
	tests := []struct {
		name          string
		componentType ComponentType
		expected      bool
	}{
		{"service", ComponentTypeService, true},
		{"worker", ComponentTypeWorker, false},
		{"app-astro", ComponentTypeAppAstro, true},
		{"app-react", ComponentTypeAppReact, true},
		{"app-nextjs", ComponentTypeAppNextJS, true},
		{"cli", ComponentTypeCLI, false},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			result := tc.componentType.NeedsPort()
			if result != tc.expected {
				t.Errorf("%s.NeedsPort() = %v, want %v", tc.componentType, result, tc.expected)
			}
		})
	}
}

func TestComponentType_IsGoComponent(t *testing.T) {
	tests := []struct {
		name          string
		componentType ComponentType
		expected      bool
	}{
		{"service", ComponentTypeService, true},
		{"worker", ComponentTypeWorker, true},
		{"app-astro", ComponentTypeAppAstro, false},
		{"app-react", ComponentTypeAppReact, false},
		{"app-nextjs", ComponentTypeAppNextJS, false},
		{"cli", ComponentTypeCLI, true},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			result := tc.componentType.IsGoComponent()
			if result != tc.expected {
				t.Errorf("%s.IsGoComponent() = %v, want %v", tc.componentType, result, tc.expected)
			}
		})
	}
}

func TestValidateComponentName(t *testing.T) {
	tests := []struct {
		name    string
		input   string
		wantErr bool
	}{
		{"valid simple", "auth", false},
		{"valid with dash", "auth-api", false},
		{"valid with numbers", "api2", false},
		{"valid complex", "user-service-v2", false},
		{"empty", "", true},
		{"starts with number", "2api", true},
		{"starts with dash", "-api", true},
		{"uppercase", "Auth", true},
		{"mixed case", "authApi", true},
		{"underscore", "auth_api", true},
		{"space", "auth api", true},
		{"special char", "auth@api", true},
		{"too long", "a" + string(make([]byte, 63)), true},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			err := ValidateComponentName(tc.input)
			if (err != nil) != tc.wantErr {
				t.Errorf("ValidateComponentName(%q) error = %v, wantErr %v", tc.input, err, tc.wantErr)
			}
		})
	}
}

func TestValidComponentTypes(t *testing.T) {
	// Ensure all valid types are in the slice
	expected := []ComponentType{
		ComponentTypeService,
		ComponentTypeWorker,
		ComponentTypeAppAstro,
		ComponentTypeAppReact,
		ComponentTypeAppNextJS,
		ComponentTypeCLI,
		ComponentTypePostgres,
		ComponentTypeRedis,
		ComponentTypeGCS,
	}

	if len(ValidComponentTypes) != len(expected) {
		t.Errorf("ValidComponentTypes has %d types, want %d", len(ValidComponentTypes), len(expected))
	}

	for i, ct := range ValidComponentTypes {
		if ct != expected[i] {
			t.Errorf("ValidComponentTypes[%d] = %s, want %s", i, ct, expected[i])
		}
	}
}

func TestComponentType_IsAppComponent(t *testing.T) {
	tests := []struct {
		name          string
		componentType ComponentType
		expected      bool
	}{
		{"service", ComponentTypeService, false},
		{"worker", ComponentTypeWorker, false},
		{"app-astro", ComponentTypeAppAstro, true},
		{"app-react", ComponentTypeAppReact, true},
		{"app-nextjs", ComponentTypeAppNextJS, true},
		{"cli", ComponentTypeCLI, false},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			result := tc.componentType.IsAppComponent()
			if result != tc.expected {
				t.Errorf("%s.IsAppComponent() = %v, want %v", tc.componentType, result, tc.expected)
			}
		})
	}
}

func TestComponentType_IsInfraComponent(t *testing.T) {
	tests := []struct {
		name          string
		componentType ComponentType
		expected      bool
	}{
		{"postgres", ComponentTypePostgres, true},
		{"redis", ComponentTypeRedis, true},
		{"service", ComponentTypeService, false},
		{"worker", ComponentTypeWorker, false},
		{"app-astro", ComponentTypeAppAstro, false},
		{"app-react", ComponentTypeAppReact, false},
		{"app-nextjs", ComponentTypeAppNextJS, false},
		{"cli", ComponentTypeCLI, false},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			result := tc.componentType.IsInfraComponent()
			if result != tc.expected {
				t.Errorf("%s.IsInfraComponent() = %v, want %v", tc.componentType, result, tc.expected)
			}
		})
	}
}
