package main

import (
	"context"
	"os"
	"os/exec"
	"path/filepath"
	"testing"
)

func TestMigrateSyncValidation(t *testing.T) {
	// Test invalid branch names
	tests := []struct {
		name    string
		branch  string
		wantErr bool
	}{
		{"valid simple", "beads-sync", false},
		{"valid with slash", "beads/sync", false},
		{"valid with dots", "beads.sync", false},
		{"invalid empty", "", true},
		{"invalid HEAD", "HEAD", true},
		{"invalid dots", "..", true},
		{"invalid leading slash", "/beads", true},
		{"invalid trailing slash", "beads/", true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// We can't easily test the full command without a git repo,
			// but we can test branch validation indirectly
			if tt.branch == "" {
				// Empty branch should fail at args validation level
				return
			}
		})
	}
}

func TestMigrateSyncDryRun(t *testing.T) {
	// Create a temp directory with a git repo
	tmpDir, err := os.MkdirTemp("", "bd-migrate-sync-test")
	if err != nil {
		t.Fatalf("failed to create temp dir: %v", err)
	}
	defer os.RemoveAll(tmpDir)

	// Initialize git repo
	cmd := exec.Command("git", "init")
	cmd.Dir = tmpDir
	if err := cmd.Run(); err != nil {
		t.Fatalf("failed to init git: %v", err)
	}

	// Configure git user for commits
	cmd = exec.Command("git", "config", "user.email", "test@test.com")
	cmd.Dir = tmpDir
	if err := cmd.Run(); err != nil {
		t.Fatalf("failed to config git email: %v", err)
	}
	cmd = exec.Command("git", "config", "user.name", "Test User")
	cmd.Dir = tmpDir
	if err := cmd.Run(); err != nil {
		t.Fatalf("failed to config git name: %v", err)
	}

	// Create initial commit
	testFile := filepath.Join(tmpDir, "test.txt")
	if err := os.WriteFile(testFile, []byte("test"), 0644); err != nil {
		t.Fatalf("failed to create test file: %v", err)
	}
	cmd = exec.Command("git", "add", ".")
	cmd.Dir = tmpDir
	if err := cmd.Run(); err != nil {
		t.Fatalf("failed to git add: %v", err)
	}
	cmd = exec.Command("git", "commit", "-m", "initial")
	cmd.Dir = tmpDir
	if err := cmd.Run(); err != nil {
		t.Fatalf("failed to git commit: %v", err)
	}

	// Create .beads directory and initialize
	beadsDir := filepath.Join(tmpDir, ".beads")
	if err := os.MkdirAll(beadsDir, 0750); err != nil {
		t.Fatalf("failed to create .beads dir: %v", err)
	}

	// Create minimal issues.jsonl
	jsonlPath := filepath.Join(beadsDir, "issues.jsonl")
	if err := os.WriteFile(jsonlPath, []byte(""), 0644); err != nil {
		t.Fatalf("failed to create issues.jsonl: %v", err)
	}

	// Test that branchExistsLocal returns false for non-existent branch
	// Note: We need to run this from tmpDir context since branchExistsLocal uses git in cwd
	ctx := context.Background()
	t.Chdir(tmpDir)

	if branchExistsLocal(ctx, "beads-sync") {
		t.Error("branchExistsLocal should return false for non-existent branch")
	}

	// Create the branch
	cmd = exec.Command("git", "branch", "beads-sync")
	cmd.Dir = tmpDir
	if err := cmd.Run(); err != nil {
		t.Fatalf("failed to create branch: %v", err)
	}

	// Now it should exist
	if !branchExistsLocal(ctx, "beads-sync") {
		t.Error("branchExistsLocal should return true for existing branch")
	}
}

func TestHasChangesInWorktreeDir(t *testing.T) {
	// Create a temp directory with a git repo
	tmpDir, err := os.MkdirTemp("", "bd-worktree-changes-test")
	if err != nil {
		t.Fatalf("failed to create temp dir: %v", err)
	}
	defer os.RemoveAll(tmpDir)

	// Initialize git repo
	cmd := exec.Command("git", "init")
	cmd.Dir = tmpDir
	if err := cmd.Run(); err != nil {
		t.Fatalf("failed to init git: %v", err)
	}

	// Configure git user
	cmd = exec.Command("git", "config", "user.email", "test@test.com")
	cmd.Dir = tmpDir
	_ = cmd.Run()
	cmd = exec.Command("git", "config", "user.name", "Test User")
	cmd.Dir = tmpDir
	_ = cmd.Run()

	// Create and commit initial file
	testFile := filepath.Join(tmpDir, "test.txt")
	if err := os.WriteFile(testFile, []byte("test"), 0644); err != nil {
		t.Fatalf("failed to create test file: %v", err)
	}
	cmd = exec.Command("git", "add", ".")
	cmd.Dir = tmpDir
	_ = cmd.Run()
	cmd = exec.Command("git", "commit", "-m", "initial")
	cmd.Dir = tmpDir
	_ = cmd.Run()

	ctx := context.Background()

	// No changes initially
	hasChanges, err := hasChangesInWorktreeDir(ctx, tmpDir)
	if err != nil {
		t.Fatalf("hasChangesInWorktreeDir failed: %v", err)
	}
	if hasChanges {
		t.Error("should have no changes initially")
	}

	// Add uncommitted file
	newFile := filepath.Join(tmpDir, "new.txt")
	if err := os.WriteFile(newFile, []byte("new"), 0644); err != nil {
		t.Fatalf("failed to create new file: %v", err)
	}

	hasChanges, err = hasChangesInWorktreeDir(ctx, tmpDir)
	if err != nil {
		t.Fatalf("hasChangesInWorktreeDir failed: %v", err)
	}
	if !hasChanges {
		t.Error("should have changes after adding file")
	}
}
