// safewrite_test.go — arcrun-rag#60 第二條：落卡前不得無條件覆蓋既有檔案。
package collector

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

// 目標不存在＝正常首次落卡，行為不變。
func TestSafeWriteCard_NewFile(t *testing.T) {
	dir := t.TempDir()
	dest := filepath.Join(dir, "sub", "foo.md")
	if err := safeWriteCard(dir, dest, []byte("# foo\n內容")); err != nil {
		t.Fatal(err)
	}
	got, err := os.ReadFile(dest)
	if err != nil {
		t.Fatal(err)
	}
	if string(got) != "# foo\n內容" {
		t.Fatalf("內容不對：%q", got)
	}
}

// 核心紅線：目標已存在且內容不同 → 先備份既有內容，不能無聲蓋掉。
func TestSafeWriteCard_ExistingFile_BacksUpBeforeOverwrite(t *testing.T) {
	dir := t.TempDir()
	dest := filepath.Join(dir, "foo.md")
	original := "# foo\n這是使用者原本就有的東西，不是 daemon 寫的"
	if err := os.WriteFile(dest, []byte(original), 0o644); err != nil {
		t.Fatal(err)
	}

	if err := safeWriteCard(dir, dest, []byte("# foo\n機器新產出的卡")); err != nil {
		t.Fatal(err)
	}

	// 新內容確實寫進去了（這是萃取的目的，不是完全拒寫）。
	got, err := os.ReadFile(dest)
	if err != nil {
		t.Fatal(err)
	}
	if string(got) != "# foo\n機器新產出的卡" {
		t.Fatalf("新內容未寫入：%q", got)
	}

	// 但舊內容必須找得到備份，不能憑空消失。
	entries, err := os.ReadDir(dir)
	if err != nil {
		t.Fatal(err)
	}
	var backup string
	for _, e := range entries {
		if strings.HasPrefix(e.Name(), "foo.md.bak-") {
			backup = filepath.Join(dir, e.Name())
		}
	}
	if backup == "" {
		t.Fatalf("沒有找到備份檔，既有內容可能已經被無聲覆蓋。目錄內容：%v", entries)
	}
	backupData, err := os.ReadFile(backup)
	if err != nil {
		t.Fatal(err)
	}
	if string(backupData) != original {
		t.Fatalf("備份內容不對：%q，want %q", backupData, original)
	}
}

// 內容完全相同（重複萃取同一份卡）＝不必動它，也不必產生垃圾備份。
func TestSafeWriteCard_SameContent_NoOp(t *testing.T) {
	dir := t.TempDir()
	dest := filepath.Join(dir, "foo.md")
	content := "# foo\n一樣的內容"
	if err := os.WriteFile(dest, []byte(content), 0o644); err != nil {
		t.Fatal(err)
	}
	if err := safeWriteCard(dir, dest, []byte(content)); err != nil {
		t.Fatal(err)
	}
	entries, _ := os.ReadDir(dir)
	if len(entries) != 1 {
		t.Fatalf("內容沒變不該產生額外檔案，目錄內容：%v", entries)
	}
}
