package config

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

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

// The deployed config.yaml is this one, env-substituted at startup, so every
// per-environment setting has to survive being unset.
func TestCutoverAndJiraConfigLoadWithAndWithoutEnv(t *testing.T) {
	path, err := filepath.Abs("../../config.yaml")
	require.NoError(t, err)

	cfg, err := Load(path)
	require.NoError(t, err, "unset env must not break config parsing")
	require.Empty(t, cfg.Jira.Project)
	require.False(t, cfg.Cutover.OwnEverything)

	t.Setenv("JIRA_PROJECT", "O11YDEV")
	t.Setenv("JIRA_SUMMARY_PREFIX", "[DEV]")
	t.Setenv("ALERTSTORE_OWN_EVERYTHING", "true")
	cfg, err = Load(path)
	require.NoError(t, err)
	require.Equal(t, "O11YDEV", cfg.Jira.Project)
	require.Equal(t, "[DEV]", cfg.Jira.SummaryPrefix)
	require.True(t, cfg.Cutover.OwnEverything)
}

// An image bump with no CD change ships this config.yaml against the existing
// env vars and no overlay; the legacy webhook token env must still resolve.
func TestDeployedConfigWebhookTokenFromEnv(t *testing.T) {
	path, err := filepath.Abs("../../config.yaml")
	require.NoError(t, err)

	t.Setenv("ALERTSTORE_WEBHOOK_TOKEN", "legacy-secret")
	cfg, err := Load(path)
	require.NoError(t, err)
	require.Equal(t, []WebhookToken{{Name: "default", Secret: "legacy-secret"}}, cfg.Webhook.Tokens())
}

func TestLoadSecretsOverlayMergesOverBase(t *testing.T) {
	dir := t.TempDir()
	base := filepath.Join(dir, "config.yaml")
	require.NoError(t, os.WriteFile(base, []byte(
		"server:\n  addr: \":9000\"\ndatabase:\n  dsn: \"${DB_DSN}\"\nwebhook:\n  alertmanager_tokens:\n    - name: default\n      secret: \"${ALERTSTORE_WEBHOOK_TOKEN}\"\n"), 0o600))
	secrets := filepath.Join(dir, "secrets.yaml")
	require.NoError(t, os.WriteFile(secrets, []byte(
		"database:\n  dsn: file-dsn\nwebhook:\n  alertmanager_tokens:\n    - name: primary\n      secret: abc\n"), 0o600))

	t.Setenv("DB_DSN", "env-dsn")
	t.Setenv("ALERTSTORE_WEBHOOK_TOKEN", "env-token")
	cfg, err := Load(base, secrets)
	require.NoError(t, err)
	// Overlay overrides the secrets it sets; base's other fields survive.
	require.Equal(t, ":9000", cfg.Server.Addr)
	require.Equal(t, "file-dsn", cfg.Database.DSN)
	// Slice fields are replaced wholesale, so the env-derived token is dropped.
	require.Equal(t, []WebhookToken{{Name: "primary", Secret: "abc"}}, cfg.Webhook.AlertmanagerTokens)
}

func TestWebhookTokensNormalizes(t *testing.T) {
	w := WebhookConfig{AlertmanagerTokens: []WebhookToken{
		{Name: " primary ", Secret: " abc "},
		{Name: "empty-secret", Secret: "  "},
		{Name: "", Secret: "def"},
	}}
	require.Equal(t, []WebhookToken{
		{Name: "primary", Secret: "abc"},
		{Name: "default", Secret: "def"},
	}, w.Tokens())
}

func TestWebhookTokensLegacyFallback(t *testing.T) {
	// Only the legacy field set (an unmigrated config.yaml): used as "default".
	legacy := WebhookConfig{AlertmanagerToken: " legacy-secret "}
	require.Equal(t, []WebhookToken{{Name: "default", Secret: "legacy-secret"}}, legacy.Tokens())

	// Structured list wins; the legacy field is ignored when the list is present.
	both := WebhookConfig{
		AlertmanagerTokens: []WebhookToken{{Name: "primary", Secret: "abc"}},
		AlertmanagerToken:  "legacy-secret",
	}
	require.Equal(t, []WebhookToken{{Name: "primary", Secret: "abc"}}, both.Tokens())
}
