package main

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

	"github.com/steveyegge/beads/internal/git"
	"github.com/steveyegge/beads/internal/storage/sqlite"
)

const windowsOS = "windows"

// ensureTestMode sets BEADS_TEST_MODE environment variable to prevent production pollution
func ensureTestMode(t *testing.T) {
	t.Helper()
	os.Setenv("BEADS_TEST_MODE", "1")
	t.Cleanup(func() {
		os.Unsetenv("BEADS_TEST_MODE")
	})
}

// failIfProductionDatabase checks if the database path is in a production directory
// and fails the test to prevent test pollution (bd-2c5a)
func failIfProductionDatabase(t *testing.T, dbPath string) {
	t.Helper()
	
	// CRITICAL (bd-2c5a): Set test mode flag
	ensureTestMode(t)
	
	// Get absolute path for comparison
	absPath, err := filepath.Abs(dbPath)
	if err != nil {
		t.Logf("Warning: Could not get absolute path for %s: %v", dbPath, err)
		return
	}
	
	// Use worktree-aware git directory detection
	gitDir, err := git.GetGitDir()
	if err != nil {
		// Not a git repository, no pollution risk
		return
	}
	
	// Check if database is in .beads/ directory of this git repository
	beadsPath := ""
	gitDirAbs, err := filepath.Abs(gitDir)
	if err != nil {
		t.Logf("Warning: Could not get absolute path for git dir %s: %v", gitDir, err)
		return
	}
	
	// The .beads directory should be at the root of the git repository
	// For worktrees, gitDir points to the main repo's .git directory
	repoRoot := filepath.Dir(gitDirAbs)
	beadsPath = filepath.Join(repoRoot, ".beads")
	
	if strings.HasPrefix(absPath, beadsPath) {
		// Database is in .beads/ directory of a git repository
		// This is ONLY allowed if we're in a temp directory
		if !strings.Contains(absPath, os.TempDir()) {
			t.Fatalf("PRODUCTION DATABASE POLLUTION DETECTED (bd-2c5a):\n"+
				"  Database: %s\n"+
				"  Git repo: %s\n"+
				"  Tests MUST use t.TempDir() or tempfile to create isolated databases.\n"+
				"  This prevents test issues from polluting the production database.",
				absPath, repoRoot)
		}
	}
}

// newTestStore creates a SQLite store with issue_prefix configured (bd-166)
// This prevents "database not initialized" errors in tests
func newTestStore(t *testing.T, dbPath string) *sqlite.SQLiteStorage {
	t.Helper()
	
	// CRITICAL (bd-2c5a): Ensure we're not polluting production database
	failIfProductionDatabase(t, dbPath)
	
	if err := os.MkdirAll(filepath.Dir(dbPath), 0755); err != nil {
		t.Fatalf("Failed to create database directory: %v", err)
	}
	
	store, err := sqlite.New(context.Background(), dbPath)
	if err != nil {
		t.Fatalf("Failed to create test database: %v", err)
	}
	
	// CRITICAL (bd-166): Set issue_prefix to prevent "database not initialized" errors
	ctx := context.Background()
	if err := store.SetConfig(ctx, "issue_prefix", "test"); err != nil {
		store.Close()
		t.Fatalf("Failed to set issue_prefix: %v", err)
	}
	
	t.Cleanup(func() { store.Close() })
	return store
}

// newTestStoreWithPrefix creates a SQLite store with custom issue_prefix configured
func newTestStoreWithPrefix(t *testing.T, dbPath string, prefix string) *sqlite.SQLiteStorage {
	t.Helper()
	
	// CRITICAL (bd-2c5a): Ensure we're not polluting production database
	failIfProductionDatabase(t, dbPath)
	
	if err := os.MkdirAll(filepath.Dir(dbPath), 0755); err != nil {
		t.Fatalf("Failed to create database directory: %v", err)
	}
	
	store, err := sqlite.New(context.Background(), dbPath)
	if err != nil {
		t.Fatalf("Failed to create test database: %v", err)
	}
	
	// CRITICAL (bd-166): Set issue_prefix to prevent "database not initialized" errors
	ctx := context.Background()
	if err := store.SetConfig(ctx, "issue_prefix", prefix); err != nil {
		store.Close()
		t.Fatalf("Failed to set issue_prefix: %v", err)
	}
	
	t.Cleanup(func() { store.Close() })
	return store
}

// openExistingTestDB opens an existing database without modifying it.
// Used in tests where the database was already created by the code under test.
func openExistingTestDB(t *testing.T, dbPath string) (*sqlite.SQLiteStorage, error) {
	t.Helper()
	return sqlite.New(context.Background(), dbPath)
}

// runCommandInDir runs a command in the specified directory
func runCommandInDir(dir string, name string, args ...string) error {
	cmd := exec.Command(name, args...)
	cmd.Dir = dir
	return cmd.Run()
}

// runCommandInDirWithOutput runs a command in the specified directory and returns its output
func runCommandInDirWithOutput(dir string, name string, args ...string) (string, error) {
	cmd := exec.Command(name, args...)
	cmd.Dir = dir
	output, err := cmd.Output()
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(string(output)), nil
}
