//go:build integration

// test_helpers_test.go 是 supervisor_test.go 的共享脚手架：
//   - notifyRepoStub：满足 notify.Repository（5 方法），让 dispatcher 落库变成空操作
//   - slogDiscard：丢弃日志的 logger
//   - encryptForTest：用与 AgentKindService 相同格式产出加密 env（map → JSON → AES-GCM）
//   - fakeAgentBinary：构建 cmd/fake-acp-agent 二进制供子进程 spawn
//
// 集成测试专用，不参与 go test 默认 build。
package acp_test

import (
	"context"
	"encoding/json"
	"io"
	"log/slog"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"testing"

	"github.com/google/uuid"
	"github.com/stretchr/testify/require"

	"github.com/yan1h/agent-coding-workflow/internal/infra/notify"
)

// notifyRepoStub 实现 notify.Repository 全部 5 方法。supervisor.onExit
// 会通过 dispatcher 落库一条 crashed 通知，落库走 stub → 永远成功 + 不存。
type notifyRepoStub struct{}

func (notifyRepoStub) Insert(context.Context, notify.Message) error { return nil }
func (notifyRepoStub) List(context.Context, uuid.UUID, bool, int) ([]notify.Message, error) {
	return nil, nil
}
func (notifyRepoStub) CountUnread(context.Context, uuid.UUID) (int, error)  { return 0, nil }
func (notifyRepoStub) MarkRead(context.Context, uuid.UUID, uuid.UUID) error { return nil }
func (notifyRepoStub) MarkAllRead(context.Context, uuid.UUID) error         { return nil }

// slogDiscard 返回静音 logger，避免测试输出污染。
func slogDiscard() *slog.Logger { return slog.New(slog.NewTextHandler(io.Discard, nil)) }

// encryptForTest 以 AgentKindService 同格式（JSON marshal → AES-GCM）产出
// EncryptedEnv 字节，让 supervisor.decryptEnv 还原为同一 map。
func encryptForTest(t *testing.T, m map[string]string) []byte {
	t.Helper()
	enc := testEncryptor(t)
	plain, err := json.Marshal(m)
	require.NoError(t, err)
	out, err := enc.Encrypt(plain)
	require.NoError(t, err)
	return out
}

// repoRoot 从测试 cwd 向上找 go.mod，返回仓库根目录。t.TempDir + go build 用。
func repoRoot(t *testing.T) string {
	t.Helper()
	wd, err := os.Getwd()
	require.NoError(t, err)
	for {
		if _, err := os.Stat(filepath.Join(wd, "go.mod")); err == nil {
			return wd
		}
		parent := filepath.Dir(wd)
		if parent == wd {
			t.Fatal("go.mod not found upward")
		}
		wd = parent
	}
}

// fakeAgentBinary 编译 cmd/fake-acp-agent 到 t.TempDir() 并返回路径。
// 测试结束后 t.TempDir 自动清理。
func fakeAgentBinary(t *testing.T) string {
	t.Helper()
	bin := filepath.Join(t.TempDir(), "fake-acp-agent")
	if runtime.GOOS == "windows" {
		bin += ".exe"
	}
	cmd := exec.Command("go", "build", "-o", bin, "./cmd/fake-acp-agent")
	cmd.Dir = repoRoot(t)
	out, err := cmd.CombinedOutput()
	require.NoError(t, err, "build fake-acp-agent: %s", out)
	return bin
}
