package cmd

import (
	"archive/tar"
	"os"
	"os/exec"
	"path/filepath"
	"testing"

	"github.com/Snider/Borg/pkg/tim"
)

func TestRunCmd_Good(t *testing.T) {
	// Create a dummy tim file.
	timPath := createDummyTim(t)

	// Mock the exec.Command function in the tim package.
	origExecCommand := tim.ExecCommand
	tim.ExecCommand = func(command string, args ...string) *exec.Cmd {
		cs := []string{"-test.run=TestHelperProcess", "--", command}
		cs = append(cs, args...)
		cmd := exec.Command(os.Args[0], cs...)
		cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
		return cmd
	}
	t.Cleanup(func() {
		tim.ExecCommand = origExecCommand
	})

	// Run the run command.
	rootCmd := NewRootCmd()
	rootCmd.AddCommand(GetRunCmd())
	_, err := executeCommand(rootCmd, "run", timPath)
	if err != nil {
		t.Fatalf("run command failed: %v", err)
	}
}

func TestRunCmd_Bad(t *testing.T) {
	t.Run("Missing input file", func(t *testing.T) {
		// Run the run command with a non-existent file.
		rootCmd := NewRootCmd()
		rootCmd.AddCommand(GetRunCmd())
		_, err := executeCommand(rootCmd, "run", "/non/existent/file.tim")
		if err == nil {
			t.Fatal("run command should have failed but did not")
		}
	})
}

func TestRunCmd_Ugly(t *testing.T) {
	t.Run("Invalid tim file", func(t *testing.T) {
		// Create an invalid (non-tar) tim file.
		tempDir := t.TempDir()
		timPath := filepath.Join(tempDir, "invalid.tim")
		err := os.WriteFile(timPath, []byte("this is not a tar file"), 0644)
		if err != nil {
			t.Fatalf("failed to create invalid tim file: %v", err)
		}

		// Run the run command.
		rootCmd := NewRootCmd()
		rootCmd.AddCommand(GetRunCmd())
		_, err = executeCommand(rootCmd, "run", timPath)
		if err == nil {
			t.Fatal("run command should have failed but did not")
		}
	})
}

// createDummyTim creates a valid, empty tim file for testing.
func createDummyTim(t *testing.T) string {
	t.Helper()
	tempDir := t.TempDir()
	timPath := filepath.Join(tempDir, "test.tim")
	timFile, err := os.Create(timPath)
	if err != nil {
		t.Fatalf("failed to create dummy tim file: %v", err)
	}
	defer timFile.Close()

	tw := tar.NewWriter(timFile)

	// Add a dummy config.json. This is not a valid config, but it's enough to test the run command.
	configContent := []byte(`{}`)
	hdr := &tar.Header{
		Name: "config.json",
		Mode: 0600,
		Size: int64(len(configContent)),
	}
	if err := tw.WriteHeader(hdr); err != nil {
		t.Fatalf("failed to write tar header: %v", err)
	}
	if _, err := tw.Write(configContent); err != nil {
		t.Fatalf("failed to write tar content: %v", err)
	}

	// Add the rootfs directory.
	hdr = &tar.Header{
		Name:     "rootfs/",
		Mode:     0755,
		Typeflag: tar.TypeDir,
	}
	if err := tw.WriteHeader(hdr); err != nil {
		t.Fatalf("failed to write tar header: %v", err)
	}

	if err := tw.Close(); err != nil {
		t.Fatalf("failed to close tar writer: %v", err)
	}
	return timPath
}

// TestHelperProcess isn't a real test. It's used as a helper for tests that need to mock exec.Command.
func TestHelperProcess(t *testing.T) {
	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
		return
	}
	// The rest of the arguments are the command and its arguments.
	// In our case, we don't need to do anything with them.
	os.Exit(0)
}
