//go:build integration

package integration

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"testing"

	"github.com/go-git/go-git/v5"
	"github.com/go-git/go-git/v5/plumbing"
)

// BenchmarkSearchCommand benchmarks the actual cheat search command
func BenchmarkSearchCommand(b *testing.B) {
	root := repoRootBench(b)

	// Build the cheat binary in .tmp (using absolute path)
	tmpDir := filepath.Join(root, ".tmp", "bench-test")
	if err := os.MkdirAll(tmpDir, 0755); err != nil {
		b.Fatalf("Failed to create temp dir: %v", err)
	}

	cheatBin := filepath.Join(tmpDir, "cheat-bench")

	// Clean up the binary when done
	b.Cleanup(func() {
		os.Remove(cheatBin)
	})

	cmd := exec.Command("go", "build", "-o", cheatBin, "./cmd/cheat")
	cmd.Dir = root
	if output, err := cmd.CombinedOutput(); err != nil {
		b.Fatalf("Failed to build cheat: %v\nOutput: %s", err, output)
	}

	// Set up test environment in .tmp
	configDir := filepath.Join(tmpDir, "config")
	cheatsheetDir := filepath.Join(configDir, "cheatsheets", "community")

	// Clone community cheatsheets (or reuse if already exists)
	if _, err := os.Stat(cheatsheetDir); os.IsNotExist(err) {
		b.Logf("Cloning community cheatsheets to %s...", cheatsheetDir)
		_, err := git.PlainClone(cheatsheetDir, false, &git.CloneOptions{
			URL:           "https://github.com/cheat/cheatsheets.git",
			Depth:         1,
			SingleBranch:  true,
			ReferenceName: plumbing.ReferenceName("refs/heads/master"),
			Progress:      nil,
		})
		if err != nil {
			b.Fatalf("Failed to clone cheatsheets: %v", err)
		}
	}

	// Create a minimal config file
	configFile := filepath.Join(configDir, "conf.yml")
	configContent := fmt.Sprintf(`---
cheatpaths:
  - name: community
    path: %s
    tags: [ community ]
    readonly: true
`, cheatsheetDir)

	if err := os.MkdirAll(configDir, 0755); err != nil {
		b.Fatalf("Failed to create config dir: %v", err)
	}
	if err := os.WriteFile(configFile, []byte(configContent), 0644); err != nil {
		b.Fatalf("Failed to write config: %v", err)
	}

	// Set environment to use our config
	env := append(os.Environ(),
		fmt.Sprintf("CHEAT_CONFIG_PATH=%s", configFile),
	)

	// Define test cases
	testCases := []struct {
		name string
		args []string
	}{
		{"SimpleSearch", []string{"-s", "echo"}},
		{"RegexSearch", []string{"-r", "-s", "^#.*example"}},
		{"ColorizedSearch", []string{"-c", "-s", "grep"}},
		{"ComplexRegex", []string{"-r", "-s", "(git|hg|svn)\\s+(add|commit|push)"}},
		{"AllCheatpaths", []string{"-a", "-s", "list"}},
	}

	// Warm up - run once to ensure everything is loaded
	warmupCmd := exec.Command(cheatBin, "-l")
	warmupCmd.Env = env
	warmupCmd.Run()

	// Run benchmarks
	for _, tc := range testCases {
		b.Run(tc.name, func(b *testing.B) {
			// Reset timer to exclude setup
			b.ResetTimer()

			for i := 0; i < b.N; i++ {
				cmd := exec.Command(cheatBin, tc.args...)
				cmd.Env = env

				var stdout, stderr bytes.Buffer
				cmd.Stdout = &stdout
				cmd.Stderr = &stderr

				err := cmd.Run()
				if err != nil {
					b.Fatalf("Command failed: %v\nStderr: %s", err, stderr.String())
				}

				if stdout.Len() == 0 {
					b.Fatal("No output from search")
				}
			}
		})
	}
}

// BenchmarkListCommand benchmarks the list command for comparison
func BenchmarkListCommand(b *testing.B) {
	root := repoRootBench(b)

	// Build the cheat binary in .tmp (using absolute path)
	tmpDir := filepath.Join(root, ".tmp", "bench-test")
	if err := os.MkdirAll(tmpDir, 0755); err != nil {
		b.Fatalf("Failed to create temp dir: %v", err)
	}

	cheatBin := filepath.Join(tmpDir, "cheat-bench")

	// Clean up the binary when done
	b.Cleanup(func() {
		os.Remove(cheatBin)
	})

	cmd := exec.Command("go", "build", "-o", cheatBin, "./cmd/cheat")
	cmd.Dir = root
	if output, err := cmd.CombinedOutput(); err != nil {
		b.Fatalf("Failed to build cheat: %v\nOutput: %s", err, output)
	}

	// Set up test environment (simplified - reuse if possible)
	configDir := filepath.Join(tmpDir, "config")
	cheatsheetDir := filepath.Join(configDir, "cheatsheets", "community")

	// Check if we need to clone
	if _, err := os.Stat(cheatsheetDir); os.IsNotExist(err) {
		_, err := git.PlainClone(cheatsheetDir, false, &git.CloneOptions{
			URL:           "https://github.com/cheat/cheatsheets.git",
			Depth:         1,
			SingleBranch:  true,
			ReferenceName: plumbing.ReferenceName("refs/heads/master"),
			Progress:      nil,
		})
		if err != nil {
			b.Fatalf("Failed to clone cheatsheets: %v", err)
		}
	}

	// Create config
	configFile := filepath.Join(configDir, "conf.yml")
	configContent := fmt.Sprintf(`---
cheatpaths:
  - name: community
    path: %s
    tags: [ community ]
    readonly: true
`, cheatsheetDir)

	os.MkdirAll(configDir, 0755)
	os.WriteFile(configFile, []byte(configContent), 0644)

	env := append(os.Environ(),
		fmt.Sprintf("CHEAT_CONFIG_PATH=%s", configFile),
	)

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		cmd := exec.Command(cheatBin, "-l")
		cmd.Env = env

		var stdout bytes.Buffer
		cmd.Stdout = &stdout

		if err := cmd.Run(); err != nil {
			b.Fatalf("Command failed: %v", err)
		}
	}
}
