package config

import (
	"encoding/json"
	"fmt"
	"path/filepath"
	"testing"
	"time"

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

func TestLoad_FromEnv(t *testing.T) {
	t.Setenv("APP_ENV", "test")
	t.Setenv("APP_HTTP_ADDR", ":9090")
	t.Setenv("APP_DB_DSN", "postgres://test")
	t.Setenv("APP_MASTER_KEY", "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff")
	t.Setenv("APP_DATA_DIR", "/tmp/acw")
	t.Setenv("APP_BOOTSTRAP_ADMIN_EMAIL", "a@b.c")
	t.Setenv("APP_BOOTSTRAP_ADMIN_PASSWORD", "pw12345678")

	cfg, err := Load("")
	require.NoError(t, err)
	require.Equal(t, "test", cfg.Env)
	require.Equal(t, ":9090", cfg.HTTP.Addr)
	require.Equal(t, "postgres://test", cfg.DB.DSN)
	require.Len(t, cfg.MasterKey, 32) // hex decoded → 32 bytes
	require.Equal(t, "/tmp/acw", cfg.DataDir)
	require.Equal(t, "a@b.c", cfg.Bootstrap.AdminEmail)
}

func TestLoad_MissingMasterKey(t *testing.T) {
	t.Setenv("APP_DB_DSN", "x")
	t.Setenv("APP_MASTER_KEY", "") // explicitly empty so t.Setenv cleans up
	_, err := Load("")
	require.Error(t, err)
	require.Contains(t, err.Error(), "MASTER_KEY")
}

func TestLoad_MasterKeyWrongLength(t *testing.T) {
	t.Setenv("APP_MASTER_KEY", "deadbeef") // too short
	t.Setenv("APP_DB_DSN", "x")
	_, err := Load("")
	require.Error(t, err)
}

func TestLoad_MasterKeyNotHex(t *testing.T) {
	t.Setenv("APP_DB_DSN", "x")
	t.Setenv("APP_MASTER_KEY", "zz") // not valid hex
	_, err := Load("")
	require.Error(t, err)
	require.Contains(t, err.Error(), "invalid hex")
}

func TestLoad_WorkspaceDefaults(t *testing.T) {
	// 验证 workspace.* 与 git.* 的默认值（含 string→time.Duration 自动解析）。
	t.Setenv("APP_DB_DSN", "postgres://x")
	t.Setenv("APP_MASTER_KEY", "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff")
	cfg, err := Load("")
	require.NoError(t, err)
	require.Equal(t, "./data", cfg.Workspace.DataDir)
	require.Equal(t, 30*time.Minute, cfg.Workspace.CloneTimeout)
	require.Equal(t, 5*time.Minute, cfg.Workspace.FetchTimeout)
	require.Equal(t, 5*time.Minute, cfg.Workspace.PushTimeout)
	require.Equal(t, 60*time.Second, cfg.Workspace.OpsTimeout)
	require.Equal(t, "git", cfg.Git.Binary)
}

func TestLoad_RunExecAllowedCommandsDefaultIsRestricted(t *testing.T) {
	t.Setenv("APP_DB_DSN", "postgres://x")
	t.Setenv("APP_MASTER_KEY", "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff")

	cfg, err := Load("")
	require.NoError(t, err)
	require.NotEmpty(t, cfg.Run.Exec.AllowedCommands)
	require.Contains(t, cfg.Run.Exec.AllowedCommands, "go")
	require.NotContains(t, cfg.Run.Exec.AllowedCommands, "sh")
	require.NotContains(t, cfg.Run.Exec.AllowedCommands, "powershell")
}

func TestLoad_ConfigExample(t *testing.T) {
	t.Setenv("APP_DB_DSN", "postgres://override")
	t.Setenv("APP_MASTER_KEY", "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff")

	cfg, err := Load(filepath.Join("..", "..", "config.example.yaml"))
	require.NoError(t, err)
	require.Equal(t, "postgres://override", cfg.DB.DSN)
	require.Equal(t, 15*time.Minute, cfg.Jobs.JobReaper.LeaseTimeout)
	require.Equal(t, 10*time.Minute, cfg.Orchestrator.TurnTimeout)
	require.NotEmpty(t, cfg.Run.Exec.AllowedCommands)
	require.True(t, cfg.HTTP.Security.Enabled)
}

func TestMasterKey_Redaction(t *testing.T) {
	k := MasterKey([]byte{0x01, 0x02, 0x03})
	require.Equal(t, "[REDACTED 32B]", k.String())
	require.Equal(t, "[REDACTED 32B]", fmt.Sprintf("%v", k))
	require.NotContains(t, fmt.Sprintf("%v", k), "01")
	b, err := json.Marshal(k)
	require.NoError(t, err)
	require.Equal(t, `"[REDACTED]"`, string(b))
}
