package main

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

func skipIfNoGit(t *testing.T) {
	t.Helper()
	if _, err := exec.LookPath("git"); err != nil {
		t.Skip("git not installed")
	}
}

func initRepo(t *testing.T, dir string) {
	t.Helper()
	mustRun := func(args ...string) {
		c := exec.Command("git", args...)
		c.Dir = dir
		c.Env = append(os.Environ(),
			"GIT_AUTHOR_NAME=test", "GIT_AUTHOR_EMAIL=test@x",
			"GIT_COMMITTER_NAME=test", "GIT_COMMITTER_EMAIL=test@x")
		out, err := c.CombinedOutput()
		if err != nil {
			t.Fatalf("git %v: %v\n%s", args, err, out)
		}
	}
	mustRun("init", "-b", "master")
	mustRun("config", "user.email", "test@x")
	mustRun("config", "user.name", "test")
}

func TestGitCommit_OK(t *testing.T) {
	skipIfNoGit(t)
	tmp := t.TempDir()
	repo := filepath.Join(tmp, "repo")
	os.MkdirAll(repo, 0755)
	initRepo(t, repo)
	os.WriteFile(filepath.Join(repo, "f.txt"), []byte("hello"), 0644)

	cap := tempCap(t, tmp+"/**")
	res, _, err := runGitCommit(cap, map[string]any{
		"repo":    repo,
		"message": "init",
		"files":   []any{"f.txt"},
	})
	if err != nil {
		t.Fatalf("commit: %v", err)
	}
	m := res.(map[string]any)
	if m["commit_sha"].(string) == "" {
		t.Fatalf("empty sha")
	}
}

func TestGitCommit_PathNotAllowed(t *testing.T) {
	skipIfNoGit(t)
	cap := tempCap(t, "/tmp/safe/**")
	_, _, err := runGitCommit(cap, map[string]any{
		"repo":    "/etc",
		"message": "evil",
	})
	if err == nil || !strings.Contains(err.Error(), "not allowed") {
		t.Fatalf("expected reject, got %v", err)
	}
}

func TestGitClone_Local(t *testing.T) {
	skipIfNoGit(t)
	tmp := t.TempDir()
	src := filepath.Join(tmp, "src")
	os.MkdirAll(src, 0755)
	initRepo(t, src)
	os.WriteFile(filepath.Join(src, "f.txt"), []byte("data"), 0644)
	c := exec.Command("git", "add", ".")
	c.Dir = src
	c.Run()
	c = exec.Command("git", "commit", "-m", "init")
	c.Dir = src
	c.Env = append(os.Environ(),
		"GIT_AUTHOR_NAME=t", "GIT_AUTHOR_EMAIL=t@x",
		"GIT_COMMITTER_NAME=t", "GIT_COMMITTER_EMAIL=t@x")
	out, err := c.CombinedOutput()
	if err != nil {
		t.Fatalf("seed commit: %v %s", err, out)
	}

	dest := filepath.Join(tmp, "clone")
	cap := tempCap(t, tmp+"/**")
	res, code, err := runGitClone(cap, map[string]any{
		"url":  src,
		"dest": dest,
	})
	if err != nil {
		t.Fatalf("clone: %v code=%d", err, code)
	}
	m := res.(map[string]any)
	if m["commit_sha"].(string) == "" {
		t.Fatalf("empty sha")
	}
	if _, err := os.Stat(filepath.Join(dest, "f.txt")); err != nil {
		t.Fatalf("file not present after clone")
	}
}

func TestGitPush_PathNotAllowed(t *testing.T) {
	skipIfNoGit(t)
	cap := tempCap(t, "/tmp/safe/**")
	_, _, err := runGitPush(cap, map[string]any{"repo": "/etc"})
	if err == nil || !strings.Contains(err.Error(), "not allowed") {
		t.Fatalf("expected reject, got %v", err)
	}
}
