package git

import (
	"os/exec"
	"slices"
	"testing"
)

func TestClient_Diff(t *testing.T) {
	var gotArgs []string
	expectedOutput := "diff --git a/file.go b/file.go\nindex 1234567..abcdefg 100644"

	client := &Client{
		execCommand: func(name string, args ...string) *exec.Cmd {
			gotArgs = append([]string{name}, args...)
			return exec.Command("echo", "-n", expectedOutput)
		},
	}

	result, err := client.Diff()
	if err != nil {
		t.Errorf("Diff() error = %v", err)
	}

	wantArgs := []string{"git", "diff"}
	if !slices.Equal(gotArgs, wantArgs) {
		t.Errorf("Diff() gotArgs = %v, want %v", gotArgs, wantArgs)
	}

	if result != expectedOutput {
		t.Errorf("Diff() result = %v, want %v", result, expectedOutput)
	}
}

func TestClient_DiffStaged(t *testing.T) {
	var gotArgs []string
	expectedOutput := "diff --git a/staged.go b/staged.go\nindex 1234567..abcdefg 100644"

	client := &Client{
		execCommand: func(name string, args ...string) *exec.Cmd {
			gotArgs = append([]string{name}, args...)
			return exec.Command("echo", "-n", expectedOutput)
		},
	}

	result, err := client.DiffStaged()
	if err != nil {
		t.Errorf("DiffStaged() error = %v", err)
	}

	wantArgs := []string{"git", "diff", "--staged"}
	if !slices.Equal(gotArgs, wantArgs) {
		t.Errorf("DiffStaged() gotArgs = %v, want %v", gotArgs, wantArgs)
	}

	if result != expectedOutput {
		t.Errorf("DiffStaged() result = %v, want %v", result, expectedOutput)
	}
}

func TestClient_DiffHead(t *testing.T) {
	var gotArgs []string
	expectedOutput := "diff --git a/head.go b/head.go\nindex 1234567..abcdefg 100644"

	client := &Client{
		execCommand: func(name string, args ...string) *exec.Cmd {
			gotArgs = append([]string{name}, args...)
			return exec.Command("echo", "-n", expectedOutput)
		},
	}

	result, err := client.DiffHead()
	if err != nil {
		t.Errorf("DiffHead() error = %v", err)
	}

	wantArgs := []string{"git", "diff", "HEAD"}
	if !slices.Equal(gotArgs, wantArgs) {
		t.Errorf("DiffHead() gotArgs = %v, want %v", gotArgs, wantArgs)
	}

	if result != expectedOutput {
		t.Errorf("DiffHead() result = %v, want %v", result, expectedOutput)
	}
}

// Error case tests for better coverage
func TestClient_Diff_Error(t *testing.T) {
	client := &Client{
		execCommand: func(name string, args ...string) *exec.Cmd {
			return exec.Command("false") // Command that always fails
		},
	}

	_, err := client.Diff()
	if err == nil {
		t.Error("Expected Diff to return an error")
	}
}

func TestClient_DiffStaged_Error(t *testing.T) {
	client := &Client{
		execCommand: func(name string, args ...string) *exec.Cmd {
			return exec.Command("false") // Command that always fails
		},
	}

	_, err := client.DiffStaged()
	if err == nil {
		t.Error("Expected DiffStaged to return an error")
	}
}

func TestClient_DiffHead_Error(t *testing.T) {
	client := &Client{
		execCommand: func(name string, args ...string) *exec.Cmd {
			return exec.Command("false") // Command that always fails
		},
	}

	_, err := client.DiffHead()
	if err == nil {
		t.Error("Expected DiffHead to return an error")
	}
}

func TestClient_DiffWith(t *testing.T) {
	var gotArgs []string
	expectedOutput := "custom diff"
	args := []string{"--staged", "HEAD~1", "--", "cmd/diff.go"}

	client := &Client{
		execCommand: func(name string, a ...string) *exec.Cmd {
			gotArgs = append([]string{name}, a...)
			return exec.Command("echo", "-n", expectedOutput)
		},
	}

	result, err := client.DiffWith(args)
	if err != nil {
		t.Fatalf("DiffWith() error = %v", err)
	}

	wantArgs := append([]string{"git", "diff"}, args...)
	if !slices.Equal(gotArgs, wantArgs) {
		t.Errorf("DiffWith() gotArgs = %v, want %v", gotArgs, wantArgs)
	}

	if result != expectedOutput {
		t.Errorf("DiffWith() result = %q, want %q", result, expectedOutput)
	}
}
