package builder

import (
	"context"
	"os/exec"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

// Save the original function to restore after tests
var originalExecCommand = exec.CommandContext

// mockCommand is used to replace exec.Command during tests
type mockCommand struct {
	cmd    *exec.Cmd
	stdout string
	stderr string
	err    error
}

// mockExecCommand creates a mock version of exec.CommandContext
func mockExecCommandContext(stdout string, stderr string, err error) func(ctx context.Context, command string, args ...string) *exec.Cmd {
	return func(ctx context.Context, command string, args ...string) *exec.Cmd {
		cmd := originalExecCommand(ctx, "echo", stdout)
		if err != nil {
			// Create a failing command that will exit with non-zero status
			cmd = originalExecCommand(ctx, "false")
		}
		return cmd
	}
}

// setupActiveBuildsTest sets up the environment for testing with active builds
func setupActiveBuildsTest(t *testing.T) func() {
	// Remember original command function to restore later
	oldExecCommand := exec.CommandContext

	// Replace exec.CommandContext with our own version that returns active builds
	exec.CommandContext = func(ctx context.Context, name string, arg ...string) *exec.Cmd {
		if name == "oc" && len(arg) > 0 && arg[0] == "get" && arg[1] == "builds" {
			// This is checking for active builds, return mock data
			cmd := exec.Command("echo", "build.build.openshift.io/test-build-1\nbuild.build.openshift.io/test-build-2")
			return cmd
		}
		// For any other command, use the original function
		return oldExecCommand(ctx, name, arg...)
	}

	// Return cleanup function to restore the original function
	return func() {
		exec.CommandContext = oldExecCommand
	}
}

// setupNoActiveBuildsTest sets up the environment for testing with no active builds
func setupNoActiveBuildsTest(t *testing.T) (func(), *bool) {
	// Remember original functions to restore later
	oldExecCommand := exec.CommandContext
	oldCreateOpenShiftGitBuildConfig := createOpenShiftGitBuildConfig

	// Track if createOpenShiftGitBuildConfig was called
	gitBuildConfigCalled := false

	// Mock exec.CommandContext to simulate no active builds
	exec.CommandContext = func(ctx context.Context, name string, arg ...string) *exec.Cmd {
		if name == "oc" && len(arg) > 0 && arg[0] == "get" && arg[1] == "builds" {
			// Return empty output for active builds query
			cmd := exec.Command("echo", "")
			return cmd
		}
		// For any other command, use the original function
		return oldExecCommand(ctx, name, arg...)
	}

	// Mock the cloneRepo and detectBuilder functionality
	// We need to temporarily replace these functions

	// Return cleanup function to restore the original functions
	return func() {
		exec.CommandContext = oldExecCommand
		createOpenShiftGitBuildConfig = oldCreateOpenShiftGitBuildConfig
	}, &gitBuildConfigCalled
}

func TestBuildWithActiveBuilds(t *testing.T) {
	// Set up test environment
	cleanup := setupActiveBuildsTest(t)
	defer cleanup()

	// Create a test builder
	builder := &Builder{
		config: &BuildConfig{
			GitURL:      "https://github.com/test/repo",
			Namespace:   "test-namespace",
			BuilderName: "static-html",
			Registry:    "test-registry",
			ImageTag:    "latest",
		},
	}

	// Test the Build method with active builds
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	imageName, err := builder.Build(ctx)
	assert.NoError(t, err, "Build should not return an error when active builds exist")

	// Verify that the image name is returned correctly
	expectedImageName := "test-registry/test-namespace/repo:latest"
	assert.Equal(t, expectedImageName, imageName, "The imageName should be correctly formed")
}

func TestBuildWithNoActiveBuilds(t *testing.T) {
	t.Skip("This test requires more complex mocking of internal methods which isn't feasible with the current code structure")

	// This test would need to mock:
	// 1. The exec.CommandContext function to return no active builds
	// 2. The builder.cloneRepo method to return a temp directory
	// 3. The builder.detectBuilder method to return a static HTML builder
	// 4. The createOpenShiftGitBuildConfig function to track it was called

	// However, these methods are not easily mockable in the current structure.
	// A refactoring of the Builder struct to accept interfaces for these
	// dependencies would make this easier to test.
}

// TestHelperFunctions verifies the helper functions used by Build
func TestHelperFunctions(t *testing.T) {
	builder := &Builder{
		config: &BuildConfig{
			GitURL:      "https://github.com/test/repo",
			Namespace:   "test-namespace",
			BuilderName: "static-html",
			Registry:    "test-registry",
			ImageTag:    "latest",
		},
	}

	// Test getRepoName
	repoName := builder.getRepoName()
	assert.Equal(t, "repo", repoName, "Repository name should be extracted correctly")

	// Test getFullImageName
	imageName := builder.getFullImageName(repoName)
	assert.Equal(t, "test-registry/test-namespace/repo:latest", imageName, "Full image name should be formed correctly")
}
