package config

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

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

func TestDevelopmentConfigMatchesLocalWorkspaceContract(t *testing.T) {
	t.Setenv("SENLIN_APP_MODE", "dev")

	cfg, err := LoadFromDir(filepath.Join("..", "..", "etc"))

	require.NoError(t, err)
	require.Equal(t, "development", cfg.Env)
	require.Equal(t, "9150", cfg.Port)
	require.Equal(t, "postgres://postgres:postgres@localhost:5432/agent_dev?sslmode=disable", cfg.DSN)
	require.NotEmpty(t, strings.TrimSpace(cfg.StorageDir))
	require.Equal(t, int64(32<<20), cfg.MaxUploadBytes)
	require.ElementsMatch(t, []string{
		"http://localhost:5173",
		"http://127.0.0.1:5173",
		"http://localhost:4173",
		"http://127.0.0.1:4173",
		"http://localhost:4174",
		"http://127.0.0.1:4174",
		"http://localhost:4175",
		"http://127.0.0.1:4175",
		"http://localhost:4176",
		"http://127.0.0.1:4176",
		"http://tauri.localhost",
	}, cfg.AllowedOrigins)
}

func TestLoadFromDirDefaultsToDevYAML(t *testing.T) {
	configDir := t.TempDir()
	writeConfig(t, configDir, "agent.dev.yaml", "development", "18080", "postgres://dev", "./dev-files", "dev-auth", "dev-system", "dev-ai")
	t.Setenv("SENLIN_APP_MODE", "")
	t.Setenv("PORT", "9999")

	cfg, err := LoadFromDir(configDir)

	require.NoError(t, err)
	require.Equal(t, "development", cfg.Env)
	require.Equal(t, "18080", cfg.Port)
	require.Equal(t, "postgres://dev", cfg.DSN)
	require.Equal(t, "./dev-files", cfg.StorageDir)
	require.Equal(t, int64(32<<20), cfg.MaxUploadBytes)
	require.Equal(t, "dev-auth", cfg.AuthSecret)
	require.Equal(t, "dev-system", cfg.SystemAIKey)
	require.Equal(t, "dev-ai", cfg.AIKeyEncryptionSecret)
	require.Equal(t, []string{"http://localhost:5173", "http://tauri.localhost"}, cfg.AllowedOrigins)
}

func TestLoadFromDirUsesSENLINAppMode(t *testing.T) {
	configDir := t.TempDir()
	writeConfig(t, configDir, "agent.dev.yaml", "development", "18080", "postgres://dev", "./dev-files", "dev-auth", "", "dev-ai")
	writeConfig(t, configDir, "agent.prod.yaml", "production", "80", "postgres://prod", "/data/files", "production-auth-signing-key-2026-safe", "prod-system", "production-ai-encryption-key-2026-safe")
	t.Setenv("SENLIN_APP_MODE", "prod")

	cfg, err := LoadFromDir(configDir)

	require.NoError(t, err)
	require.Equal(t, "production", cfg.Env)
	require.Equal(t, "80", cfg.Port)
	require.Equal(t, "postgres://prod", cfg.DSN)
	require.Equal(t, "/data/files", cfg.StorageDir)
	require.Equal(t, "production-auth-signing-key-2026-safe", cfg.AuthSecret)
	require.Equal(t, "prod-system", cfg.SystemAIKey)
	require.Equal(t, "production-ai-encryption-key-2026-safe", cfg.AIKeyEncryptionSecret)
	require.Equal(t, []string{"https://workbench.example.com"}, cfg.AllowedOrigins)
}

func TestLoadFromDirRejectsMissingStorageDir(t *testing.T) {
	configDir := t.TempDir()
	writeConfig(t, configDir, "agent.dev.yaml", "development", "9150", "postgres://agent", "", "dev-auth", "", "dev-ai")
	t.Setenv("SENLIN_APP_MODE", "dev")

	_, err := LoadFromDir(configDir)

	require.ErrorContains(t, err, "storage_dir")
}

func TestLoadFromDirRejectsMissingAllowedOrigins(t *testing.T) {
	configDir := t.TempDir()
	content := []byte("env: development\n" +
		"port: \"9150\"\n" +
		"dsn: \"postgres://agent\"\n" +
		"storage_dir: \"./data/files\"\n" +
		"auth_secret: \"dev-auth\"\n" +
		"ai_key_encryption_secret: \"dev-ai\"\n")
	require.NoError(t, os.WriteFile(filepath.Join(configDir, "agent.dev.yaml"), content, 0o600))
	t.Setenv("SENLIN_APP_MODE", "dev")

	_, err := LoadFromDir(configDir)

	require.ErrorContains(t, err, "allowed_origins")
}

func TestLoadFromDirRejectsUnsafeProductionSecrets(t *testing.T) {
	tests := []struct {
		name              string
		authSecret        string
		encryptionSecret  string
		expectedFieldName string
	}{
		{name: "empty auth", authSecret: "", encryptionSecret: "production-ai-encryption-key-2026-safe", expectedFieldName: "auth_secret"},
		{name: "short auth", authSecret: "short", encryptionSecret: "production-ai-encryption-key-2026-safe", expectedFieldName: "auth_secret"},
		{name: "development auth sentinel", authSecret: "development-auth-secret-change-me", encryptionSecret: "production-ai-encryption-key-2026-safe", expectedFieldName: "auth_secret"},
		{name: "dev auth sentinel", authSecret: "dev-secret-dev-secret-dev-secret-000", encryptionSecret: "production-ai-encryption-key-2026-safe", expectedFieldName: "auth_secret"},
		{name: "empty encryption", authSecret: "production-auth-signing-key-2026-safe", encryptionSecret: "", expectedFieldName: "ai_key_encryption_secret"},
		{name: "short encryption", authSecret: "production-auth-signing-key-2026-safe", encryptionSecret: "short", expectedFieldName: "ai_key_encryption_secret"},
		{name: "common encryption sentinel", authSecret: "production-auth-signing-key-2026-safe", encryptionSecret: "change-me-change-me-change-me-change-me", expectedFieldName: "ai_key_encryption_secret"},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			configDir := t.TempDir()
			writeConfig(t, configDir, "agent.prod.yaml", "production", "80", "postgres://prod", "/data/files", test.authSecret, "", test.encryptionSecret)
			t.Setenv("SENLIN_APP_MODE", "prod")

			_, err := LoadFromDir(configDir)

			require.ErrorContains(t, err, test.expectedFieldName)
		})
	}
}

func TestLoadFromDirRequiresExplicitDevelopmentSecrets(t *testing.T) {
	for _, missingField := range []string{"auth", "encryption"} {
		t.Run(missingField, func(t *testing.T) {
			configDir := t.TempDir()
			authSecret, encryptionSecret := "development-auth", "development-encryption"
			if missingField == "auth" {
				authSecret = ""
			} else {
				encryptionSecret = ""
			}
			writeConfig(t, configDir, "agent.dev.yaml", "development", "9150", "postgres://dev", "./files", authSecret, "", encryptionSecret)
			t.Setenv("SENLIN_APP_MODE", "dev")

			_, err := LoadFromDir(configDir)

			require.Error(t, err)
		})
	}
}

func TestLoadFromDirAllowsExplicitTestSecrets(t *testing.T) {
	configDir := t.TempDir()
	writeConfig(t, configDir, "agent.test.yaml", "test", "9150", "postgres://test", "./files", "test-auth", "", "test-ai")
	t.Setenv("SENLIN_APP_MODE", "test")

	cfg, err := LoadFromDir(configDir)

	require.NoError(t, err)
	require.Equal(t, "test-auth", cfg.AuthSecret)
	require.Equal(t, "test-ai", cfg.AIKeyEncryptionSecret)
}

func writeConfig(t *testing.T, dir string, name string, env string, port string, databaseURL string, storageDir string, authSecret string, systemAIKey string, aiKeySecret string) {
	t.Helper()
	allowedOrigins := "  - http://localhost:5173\n  - http://tauri.localhost\n"
	if env == "production" {
		allowedOrigins = "  - https://workbench.example.com\n"
	}
	content := []byte("env: " + env + "\n" +
		"port: \"" + port + "\"\n" +
		"dsn: \"" + databaseURL + "\"\n" +
		"storage_dir: \"" + storageDir + "\"\n" +
		"auth_secret: \"" + authSecret + "\"\n" +
		"system_ai_key: \"" + systemAIKey + "\"\n" +
		"ai_key_encryption_secret: \"" + aiKeySecret + "\"\n" +
		"allowed_origins:\n" + allowedOrigins)
	require.NoError(t, os.WriteFile(filepath.Join(dir, name), content, 0o600))
}
