package gittransport

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"os"
	"os/exec"
	"path/filepath"
	"testing"

	reposync "github.com/pingcap/agent-git-service/internal/sync"
)

func TestParseLFSPointer(t *testing.T) {
	oid := "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
	pointer, ok := parseLFSPointer([]byte("version https://git-lfs.github.com/spec/v1\noid sha256:" + oid + "\nsize 42\n"))
	if !ok || pointer.OID != oid || pointer.Size != 42 {
		t.Fatalf("pointer = %#v ok=%t", pointer, ok)
	}
	if _, ok := parseLFSPointer([]byte("oid sha256:" + oid)); ok {
		t.Fatal("malformed pointer was accepted")
	}
}

func TestInventoryLFSFindsUniqueReachablePointers(t *testing.T) {
	repository := filepath.Join(t.TempDir(), "repo")
	runTestGit(t, "", "init", repository)
	runTestGit(t, repository, "config", "user.email", "test@example.com")
	runTestGit(t, repository, "config", "user.name", "Test")
	oid := "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
	pointer := "version https://git-lfs.github.com/spec/v1\noid sha256:" + oid + "\nsize 42\n"
	if err := os.WriteFile(filepath.Join(repository, "asset.bin"), []byte(pointer), 0o644); err != nil {
		t.Fatal(err)
	}
	runTestGit(t, repository, "add", "asset.bin")
	runTestGit(t, repository, "commit", "-m", "add pointer")
	objects, err := InventoryLFS(context.Background(), reposync.GitRemote{URL: repository})
	if err != nil {
		t.Fatalf("InventoryLFS: %v", err)
	}
	if len(objects) != 1 || objects[0].Identity != oid || objects[0].ObjectType != "lfs_objects" {
		t.Fatalf("objects = %#v", objects)
	}
}

func TestVerifyLocalLFSObjectChecksSizeAndHash(t *testing.T) {
	repository := t.TempDir()
	payload := []byte("durable-lfs-data")
	sum := sha256.Sum256(payload)
	oid := hex.EncodeToString(sum[:])
	path := filepath.Join(repository, "lfs", "objects", oid[:2], oid[2:4], oid)
	if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
		t.Fatal(err)
	}
	if err := os.WriteFile(path, payload, 0o444); err != nil {
		t.Fatal(err)
	}
	if err := verifyLocalLFSObject(repository, oid, int64(len(payload))); err != nil {
		t.Fatalf("verifyLocalLFSObject: %v", err)
	}
	if err := verifyLocalLFSObject(repository, oid, int64(len(payload)+1)); err == nil {
		t.Fatal("size mismatch was accepted")
	}
}

func runTestGit(t *testing.T, dir string, args ...string) {
	t.Helper()
	command := exec.Command("git", args...)
	command.Dir = dir
	if output, err := command.CombinedOutput(); err != nil {
		t.Fatalf("git %v: %v: %s", args, err, output)
	}
}
