package cmd

import (
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/twpayne/go-vfs/v2"
	"github.com/twpayne/go-vfs/v2/vfst"

	"github.com/twpayne/chezmoi/v2/internal/chezmoitest"
)

func TestDiffCmd(t *testing.T) {
	if chezmoitest.Umask != 0o22 {
		t.Skip("umask not 0o22")
	}
	for _, tc := range []struct {
		name      string
		extraRoot interface{}
		args      []string
		stdoutStr string
	}{
		{
			name: "empty",
		},
		{
			name: "file",
			extraRoot: map[string]interface{}{
				"/home/user/.local/share/chezmoi": map[string]interface{}{
					"dot_file": "# contents of .file\n",
				},
			},
			stdoutStr: chezmoitest.JoinLines(
				`diff --git a/.file b/.file`,
				`new file mode 100644`,
				`index 0000000000000000000000000000000000000000..8a52cb9ce9551221716a53786ad74104c5902362`,
				`--- /dev/null`,
				`+++ b/.file`,
				`@@ -0,0 +1 @@`,
				`+# contents of .file`,
			),
		},
		{
			name: "simple_exclude_files",
			extraRoot: map[string]interface{}{
				"/home/user/.local/share/chezmoi": map[string]interface{}{
					"dot_file":            "# contents of .file\n",
					"symlink_dot_symlink": ".file\n",
				},
			},
			args: []string{
				"--exclude", "files",
			},
			stdoutStr: chezmoitest.JoinLines(
				`diff --git a/.symlink b/.symlink`,
				`new file mode 120000`,
				`index 0000000000000000000000000000000000000000..3e6844d17780d623d817c3e22bcd1128d64422ae`,
				`--- /dev/null`,
				`+++ b/.symlink`,
				`@@ -0,0 +1 @@`,
				`+.file`,
			),
		},
		{
			name: "simple_exclude_files_with_config",
			extraRoot: map[string]interface{}{
				"/home/user": map[string]interface{}{
					".config/chezmoi/chezmoi.toml": chezmoitest.JoinLines(
						`[diff]`,
						`  exclude = ["files"]`,
					),
					".local/share/chezmoi": map[string]interface{}{
						"dot_file":            "# contents of .file\n",
						"symlink_dot_symlink": ".file\n",
					},
				},
			},
			stdoutStr: chezmoitest.JoinLines(
				`diff --git a/.symlink b/.symlink`,
				`new file mode 120000`,
				`index 0000000000000000000000000000000000000000..3e6844d17780d623d817c3e22bcd1128d64422ae`,
				`--- /dev/null`,
				`+++ b/.symlink`,
				`@@ -0,0 +1 @@`,
				`+.file`,
			),
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			chezmoitest.WithTestFS(t, map[string]interface{}{
				"/home/user": &vfst.Dir{Perm: 0o777 &^ chezmoitest.Umask},
			}, func(fs vfs.FS) {
				if tc.extraRoot != nil {
					require.NoError(t, vfst.NewBuilder().Build(fs, tc.extraRoot))
				}
				var stdout strings.Builder
				require.NoError(t, newTestConfig(t, fs, withStdout(&stdout)).execute(append([]string{"diff"}, tc.args...)))
				assert.Equal(t, tc.stdoutStr, stdout.String())
			})
		})
	}
}
