package handlers

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

// TestValidateRepoPath tests the security validation for repository paths
func TestValidateRepoPath(t *testing.T) {
	// Get project root (two levels up from handlers directory)
	cwd, err := os.Getwd()
	if err != nil {
		t.Fatalf("Failed to get working directory: %v", err)
	}
	// Navigate to project root
	projectRoot := filepath.Join(cwd, "..", "..")

	tests := []struct {
		name      string
		path      string
		shouldErr bool
		errMsg    string
	}{
		{
			name:      "Valid path within project",
			path:      projectRoot,
			shouldErr: false,
		},
		{
			name:      "Valid subdirectory",
			path:      filepath.Join(projectRoot, "data"),
			shouldErr: false,
		},
		{
			name:      "Path traversal attack - parent directory",
			path:      "../../../etc/passwd",
			shouldErr: true,
			errMsg:    "repository path outside project directory",
		},
		{
			name:      "Path traversal attack - absolute path",
			path:      "/etc/passwd",
			shouldErr: true,
			errMsg:    "repository path outside project directory",
		},
		{
			name:      "Command injection attempt - pipe",
			path:      "data | cat /etc/passwd",
			shouldErr: true,
			errMsg:    "path does not exist",
		},
		{
			name:      "Command injection attempt - semicolon",
			path:      "data; rm -rf /",
			shouldErr: true,
			errMsg:    "path does not exist",
		},
		{
			name:      "Command injection attempt - backticks",
			path:      "data`whoami`",
			shouldErr: true,
			errMsg:    "path does not exist",
		},
		{
			name:      "Non-existent path",
			path:      filepath.Join(projectRoot, "nonexistent-directory-12345"),
			shouldErr: true,
			errMsg:    "path does not exist",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := validateRepoPath(tt.path)

			if tt.shouldErr {
				if err == nil {
					t.Errorf("Expected error for path %q, got nil", tt.path)
					return
				}
				if tt.errMsg != "" && err.Error() != "" {
					// Check if error message contains expected substring
					if !contains(err.Error(), tt.errMsg) {
						t.Errorf("Expected error containing %q, got %q", tt.errMsg, err.Error())
					}
				}
			} else {
				if err != nil {
					t.Errorf("Unexpected error for valid path %q: %v", tt.path, err)
				}
			}
		})
	}
}

// TestGetGitRepoFirstCommitDate_SecurityValidation tests that malicious paths are rejected
func TestGetGitRepoFirstCommitDate_SecurityValidation(t *testing.T) {
	maliciousPaths := []string{
		"../../../etc/passwd",
		"/etc/passwd",
		"data | cat /etc/passwd",
		"data; whoami",
		"data`id`",
		"$(whoami)",
	}

	for _, path := range maliciousPaths {
		t.Run("Reject_"+path, func(t *testing.T) {
			// Should return empty string (safe rejection)
			result := getGitRepoFirstCommitDate(path)
			if result != "" {
				t.Errorf("Expected empty result for malicious path %q, got %q", path, result)
			}
		})
	}
}

// TestGetGitRepoFirstCommitDate_Timeout tests that git commands timeout appropriately
func TestGetGitRepoFirstCommitDate_Timeout(t *testing.T) {
	// Create a temporary directory that exists but is not a git repo
	tempDir := t.TempDir()

	// This should timeout/fail gracefully (not hang)
	result := getGitRepoFirstCommitDate(tempDir)

	// Should return empty string for non-git repos
	if result != "" {
		t.Errorf("Expected empty result for non-git directory, got %q", result)
	}
}

// Helper function to check if a string contains a substring
func contains(s, substr string) bool {
	return len(s) >= len(substr) && (s == substr || len(substr) == 0 ||
		(len(s) > 0 && len(substr) > 0 && stringContains(s, substr)))
}

func stringContains(s, substr string) bool {
	for i := 0; i <= len(s)-len(substr); i++ {
		if s[i:i+len(substr)] == substr {
			return true
		}
	}
	return false
}
