package gitstore_test

import (
	"context"
	"testing"

	"github.com/pingcap/agent-git-service/internal/gitstore"
)

func TestStore_MergeStackAtomicallyAndCascade(t *testing.T) {
	store, cleanup := gitstore.NewTestStore(t)
	defer cleanup()
	ctx := context.Background()
	fullName := "stack-owner/stack-repo"
	if err := store.Init(ctx, fullName, "main", true); err != nil {
		t.Fatal(err)
	}
	if _, err := store.WriteFile(ctx, fullName, "main", "base.txt", "base", []byte("base\n")); err != nil {
		t.Fatal(err)
	}
	if err := store.CreateBranch(ctx, fullName, "stack-one", "main"); err != nil {
		t.Fatal(err)
	}
	if _, err := store.WriteFile(ctx, fullName, "stack-one", "one.txt", "one", []byte("one\n")); err != nil {
		t.Fatal(err)
	}
	if err := store.CreateBranch(ctx, fullName, "stack-two", "stack-one"); err != nil {
		t.Fatal(err)
	}
	if _, err := store.WriteFile(ctx, fullName, "stack-two", "two.txt", "two", []byte("two\n")); err != nil {
		t.Fatal(err)
	}
	oldTwoSHA, err := store.HeadSHA(ctx, fullName, "stack-two")
	if err != nil {
		t.Fatal(err)
	}
	if err := store.CreateBranch(ctx, fullName, "stack-three", "stack-two"); err != nil {
		t.Fatal(err)
	}
	if _, err := store.WriteFile(ctx, fullName, "stack-three", "three.txt", "three", []byte("three\n")); err != nil {
		t.Fatal(err)
	}

	mergeResult, err := store.MergeStackAtomicallyDetailed(ctx, gitstore.StackMergeOptions{
		FullName: fullName, BaseBranch: "main", MergeMethod: "squash", Committer: "Stack Bot", Email: "stack@example.com",
		Members: []gitstore.StackMergeMember{
			{Number: 1, BaseBranch: "main", HeadBranch: "stack-one", Message: "merge one"},
			{Number: 2, BaseBranch: "stack-one", HeadBranch: "stack-two", Message: "merge two"},
		},
	})
	if err != nil {
		t.Fatalf("MergeStackAtomicallyDetailed: %v", err)
	}
	mergedSHA := mergeResult.FinalSHA
	if len(mergeResult.MemberSHAs) != 2 || mergeResult.MemberSHAs[0] == mergeResult.MemberSHAs[1] || mergeResult.MemberSHAs[1] != mergedSHA {
		t.Fatalf("member SHAs = %v, final = %q", mergeResult.MemberSHAs, mergedSHA)
	}
	mainSHA, err := store.HeadSHA(ctx, fullName, "main")
	if err != nil || mainSHA != mergedSHA {
		t.Fatalf("main SHA = %q, %v; want %q", mainSHA, err, mergedSHA)
	}

	updated, err := store.CascadeRebaseStack(ctx, gitstore.StackCascadeOptions{
		FullName: fullName, NewBaseSHA: mergedSHA,
		Remaining: []gitstore.StackCascadeMember{{BaseBranch: "stack-two", HeadBranch: "stack-three", OldBaseSHA: oldTwoSHA}},
		Committer: "Stack Bot", Email: "stack@example.com",
	})
	if err != nil {
		t.Fatalf("CascadeRebaseStack: %v", err)
	}
	if sha, err := store.HeadSHA(ctx, fullName, "stack-two"); err != nil || sha != oldTwoSHA {
		t.Fatalf("merged Stack branch was rewritten: SHA = %q, %v; want %q", sha, err, oldTwoSHA)
	}
	threeSHA, err := store.HeadSHA(ctx, fullName, "stack-three")
	if err != nil {
		t.Fatal(err)
	}
	if threeSHA != updated["stack-three"] {
		t.Fatalf("stack-three SHA = %q, want returned %q", threeSHA, updated["stack-three"])
	}
	repoPath, err := store.GetRepoPath(ctx, fullName)
	if err != nil {
		t.Fatal(err)
	}
	parent := runGit(t, repoPath, "rev-parse", threeSHA+"^")
	if parent != mergedSHA+"\n" {
		t.Fatalf("stack-three parent = %q, want %q", parent, mergedSHA)
	}
}
