package cli

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

	"gitlab.com/M0M097/pkg/internal/must"
)

func TestPager(t *testing.T) {
	const FALLBACK_PAGER = "cat"
	origPager := os.Getenv("PAGER")
	defer os.Setenv("PAGER", origPager)

	devnull, _ := os.Open(os.DevNull)
	defer devnull.Close()
	for _, tt := range []struct {
		name string
		env  string
		want string
	}{
		{name: "env pager", env: "cat", want: "foo\n"},
		{name: "fallback pager", env: "", want: "bar\n"},
	} {
		t.Run(tt.name, func(t *testing.T) {
			var stdout, stderr strings.Builder
			exec := Executor{Stdout: &stdout, Stderr: &stderr}
			if tt.env == "" {
				os.Unsetenv("PAGER")
			} else {
				os.Setenv("PAGER", tt.env)
			}
			pager := Pager(exec, FALLBACK_PAGER)
			testFile := must.Content2File(filepath.Join(t.TempDir(), "test.txt"), tt.want)
			if err := pager(testFile); err != nil {
				t.Fatal(err)
			}
			if stdout.String() != tt.want {
				t.Errorf("Pager() output %q, want %q", stdout.String(), tt.want)
			}
			if stderr.String() != "" {
				t.Errorf("Pager() stderr %q, want empty", stderr.String())
			}
		})
	}
}

func TestRun(t *testing.T) {
	dummyStdout, dummyStderr := strings.Builder{}, strings.Builder{}
	devnull, _ := os.Open(os.DevNull)
	defer devnull.Close()
	executor := Executor{Stdout: &dummyStdout, Stderr: &dummyStderr}
	err := executor.Run("echo foo")
	if err != nil {
		t.Error("Run() returned an error")
	}
	if dummyStdout.String() != "foo\n" {
		t.Error("Run() returned an incorrect stdout")
	}
	if dummyStderr.String() != "" {
		t.Error("Run() returned an incorrect stderr")
	}
}

func TestRunReturnsErrorWithoutLoggingIt(t *testing.T) {
	dummyStdout, dummyStderr := strings.Builder{}, strings.Builder{}
	logBuf := withCapturedLog(t)
	executor := Executor{Stdout: &dummyStdout, Stderr: &dummyStderr}

	err := executor.Run("false")
	if err == nil {
		t.Fatal("Run() returned nil error")
	}
	if !strings.Contains(err.Error(), "false failed") {
		t.Fatalf("Run() returned unexpected error: %v", err)
	}
	if got := logBuf.String(); got != "" {
		t.Errorf("Run() logged failure %q, want empty log", got)
	}
}

func TestRunLogsCommandWhenEnabled(t *testing.T) {
	dummyStdout, dummyStderr := strings.Builder{}, strings.Builder{}
	devnull, _ := os.Open(os.DevNull)
	defer devnull.Close()
	logBuf := withCapturedLog(t)
	executor := Executor{Stdout: &dummyStdout, Stderr: &dummyStderr, Log: true}

	if err := executor.Run("true"); err != nil {
		t.Fatal(err)
	}
	if got := logBuf.String(); !strings.Contains(got, "true") {
		t.Errorf("Run() log %q, want command", got)
	}
}

func TestDisplay(t *testing.T) {
	dummyStdout, dummyStderr := strings.Builder{}, strings.Builder{}
	devnull, _ := os.Open(os.DevNull)
	defer devnull.Close()
	executor := Executor{Stdout: &dummyStdout, Stderr: &dummyStderr}
	pager := Pager(executor, "cat")
	td := t.TempDir()
	testFile := must.Content2File(filepath.Join(td, "test.txt"), "foo\nbar")
	if err := pager(testFile); err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(dummyStdout.String(), "foo\nbar") {
		t.Error("Display() did not output the expected content")
	}
}
