//go:build integration
// +build integration

package main

import (
	"bytes"
	"context"
	"encoding/json"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"

	"github.com/steveyegge/beads/internal/types"
)

// TestImportWarnsUncommittedChanges tests bd-u4f5
// Import should warn when database matches working tree but not git HEAD
func TestImportWarnsUncommittedChanges(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping git-dependent test in short mode")
	}

	// Create temporary directory with git repo
	tmpDir, err := os.MkdirTemp("", "beads-test-")
	if err != nil {
		t.Fatalf("Failed to create temp dir: %v", err)
	}
	defer os.RemoveAll(tmpDir)

	// Initialize git repo
	gitInit := exec.Command("git", "init")
	gitInit.Dir = tmpDir
	if err := gitInit.Run(); err != nil {
		t.Fatalf("Failed to init git: %v", err)
	}

	// Configure git user
	gitConfig1 := exec.Command("git", "config", "user.email", "test@example.com")
	gitConfig1.Dir = tmpDir
	if err := gitConfig1.Run(); err != nil {
		t.Fatalf("Failed to configure git: %v", err)
	}
	gitConfig2 := exec.Command("git", "config", "user.name", "Test User")
	gitConfig2.Dir = tmpDir
	if err := gitConfig2.Run(); err != nil {
		t.Fatalf("Failed to configure git: %v", err)
	}

	// Create .beads directory
	beadsDir := filepath.Join(tmpDir, ".beads")
	if err := os.MkdirAll(beadsDir, 0755); err != nil {
		t.Fatalf("Failed to create .beads dir: %v", err)
	}

	dbPath := filepath.Join(beadsDir, "beads.db")
	jsonlPath := filepath.Join(beadsDir, "issues.jsonl")

	// Initialize database
	store := newTestStore(t, dbPath)
	ctx := context.Background()

	// Step 1: Create initial issue and export
	issue1 := &types.Issue{
		ID:          "test-1",
		Title:       "Original Issue",
		Description: "Original description",
		Status:      types.StatusOpen,
		Priority:    2,
		IssueType:   types.TypeTask,
	}

	if err := store.CreateIssue(ctx, issue1, "test"); err != nil {
		t.Fatalf("Failed to create issue: %v", err)
	}

	// Export to JSONL
	issues, err := store.SearchIssues(ctx, "", types.IssueFilter{})
	if err != nil {
		t.Fatalf("Failed to search issues: %v", err)
	}

	f, err := os.Create(jsonlPath)
	if err != nil {
		t.Fatalf("Failed to create JSONL: %v", err)
	}
	encoder := json.NewEncoder(f)
	for _, issue := range issues {
		if err := encoder.Encode(issue); err != nil {
			f.Close()
			t.Fatalf("Failed to encode issue: %v", err)
		}
	}
	f.Close()

	// Commit the initial JSONL to git
	gitAdd := exec.Command("git", "add", ".beads/issues.jsonl")
	gitAdd.Dir = tmpDir
	if err := gitAdd.Run(); err != nil {
		t.Fatalf("Failed to git add: %v", err)
	}

	gitCommit := exec.Command("git", "commit", "-m", "Initial commit")
	gitCommit.Dir = tmpDir
	if err := gitCommit.Run(); err != nil {
		t.Fatalf("Failed to git commit: %v", err)
	}

	// Step 2: Add a new issue to database and export (creating uncommitted change)
	issue2 := &types.Issue{
		ID:          "test-2",
		Title:       "New Issue",
		Description: "New description",
		Status:      types.StatusOpen,
		Priority:    1,
		IssueType:   types.TypeBug,
	}

	if err := store.CreateIssue(ctx, issue2, "test"); err != nil {
		t.Fatalf("Failed to create second issue: %v", err)
	}

	// Export again (now JSONL has 2 issues, but git HEAD has 1)
	issues, err = store.SearchIssues(ctx, "", types.IssueFilter{})
	if err != nil {
		t.Fatalf("Failed to search issues: %v", err)
	}

	f, err = os.Create(jsonlPath)
	if err != nil {
		t.Fatalf("Failed to recreate JSONL: %v", err)
	}
	encoder = json.NewEncoder(f)
	for _, issue := range issues {
		if err := encoder.Encode(issue); err != nil {
			f.Close()
			t.Fatalf("Failed to encode issue: %v", err)
		}
	}
	f.Close()

	// Step 3: Run import and capture output
	// Database already matches working tree, so import will report 0 created, 0 updated
	// But working tree differs from git HEAD, so we should see a warning

	opts := ImportOptions{
		DryRun:     false,
		SkipUpdate: false,
		Strict:     false,
	}

	// Read JSONL for import
	importData, err := os.ReadFile(jsonlPath)
	if err != nil {
		t.Fatalf("Failed to read JSONL: %v", err)
	}

	var importIssues []*types.Issue
	lines := bytes.Split(importData, []byte("\n"))
	for _, line := range lines {
		if len(line) == 0 {
			continue
		}
		var issue types.Issue
		if err := json.Unmarshal(line, &issue); err != nil {
			t.Fatalf("Failed to unmarshal: %v", err)
		}
		importIssues = append(importIssues, &issue)
	}

	result, err := importIssuesCore(ctx, dbPath, store, importIssues, opts)
	if err != nil {
		t.Fatalf("Import failed: %v", err)
	}

	// Verify no changes (database already synced)
	if result.Created != 0 || result.Updated != 0 {
		t.Errorf("Expected 0 created, 0 updated, got created=%d updated=%d", result.Created, result.Updated)
	}

	// Now test the warning detection function directly
	// Capture stderr to check for warning
	oldStderr := os.Stderr
	r, w, _ := os.Pipe()
	os.Stderr = w

	checkUncommittedChanges(jsonlPath, result)

	w.Close()
	os.Stderr = oldStderr

	var buf bytes.Buffer
	buf.ReadFrom(r)
	output := buf.String()

	// Verify warning is present
	if !strings.Contains(output, "Warning") {
		t.Errorf("Expected warning about uncommitted changes, got: %s", output)
	}
	if !strings.Contains(output, "uncommitted changes") {
		t.Errorf("Expected warning to mention 'uncommitted changes', got: %s", output)
	}
	if !strings.Contains(output, "Working tree:") {
		t.Errorf("Expected warning to show working tree line count, got: %s", output)
	}
	if !strings.Contains(output, "database already synced with working tree") {
		t.Errorf("Expected warning to clarify sync status, got: %s", output)
	}
	// Git HEAD line count is optional - may not show if git command fails
	// The important part is that we detect uncommitted changes at all
}

// TestImportNoWarningWhenClean tests that import doesn't warn when working tree matches git HEAD
func TestImportNoWarningWhenClean(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping git-dependent test in short mode")
	}

	// Create temporary directory with git repo
	tmpDir, err := os.MkdirTemp("", "beads-test-")
	if err != nil {
		t.Fatalf("Failed to create temp dir: %v", err)
	}
	defer os.RemoveAll(tmpDir)

	// Initialize git repo
	gitInit := exec.Command("git", "init")
	gitInit.Dir = tmpDir
	if err := gitInit.Run(); err != nil {
		t.Fatalf("Failed to init git: %v", err)
	}

	// Configure git user
	gitConfig1 := exec.Command("git", "config", "user.email", "test@example.com")
	gitConfig1.Dir = tmpDir
	if err := gitConfig1.Run(); err != nil {
		t.Fatalf("Failed to configure git: %v", err)
	}
	gitConfig2 := exec.Command("git", "config", "user.name", "Test User")
	gitConfig2.Dir = tmpDir
	if err := gitConfig2.Run(); err != nil {
		t.Fatalf("Failed to configure git: %v", err)
	}

	// Create .beads directory
	beadsDir := filepath.Join(tmpDir, ".beads")
	if err := os.MkdirAll(beadsDir, 0755); err != nil {
		t.Fatalf("Failed to create .beads dir: %v", err)
	}

	dbPath := filepath.Join(beadsDir, "beads.db")
	jsonlPath := filepath.Join(beadsDir, "issues.jsonl")

	// Initialize database
	store := newTestStore(t, dbPath)
	ctx := context.Background()

	// Create and export issue
	issue := &types.Issue{
		ID:          "test-1",
		Title:       "Test Issue",
		Description: "Test description",
		Status:      types.StatusOpen,
		Priority:    2,
		IssueType:   types.TypeTask,
	}

	if err := store.CreateIssue(ctx, issue, "test"); err != nil {
		t.Fatalf("Failed to create issue: %v", err)
	}

	// Export to JSONL
	issues, err := store.SearchIssues(ctx, "", types.IssueFilter{})
	if err != nil {
		t.Fatalf("Failed to search issues: %v", err)
	}

	f, err := os.Create(jsonlPath)
	if err != nil {
		t.Fatalf("Failed to create JSONL: %v", err)
	}
	encoder := json.NewEncoder(f)
	for _, issue := range issues {
		if err := encoder.Encode(issue); err != nil {
			f.Close()
			t.Fatalf("Failed to encode issue: %v", err)
		}
	}
	f.Close()

	// Commit to git (now working tree matches HEAD)
	gitAdd := exec.Command("git", "add", ".beads/issues.jsonl")
	gitAdd.Dir = tmpDir
	if err := gitAdd.Run(); err != nil {
		t.Fatalf("Failed to git add: %v", err)
	}

	gitCommit := exec.Command("git", "commit", "-m", "Commit JSONL")
	gitCommit.Dir = tmpDir
	if err := gitCommit.Run(); err != nil {
		t.Fatalf("Failed to git commit: %v", err)
	}

	// Run import
	opts := ImportOptions{
		DryRun:     false,
		SkipUpdate: false,
		Strict:     false,
	}

	importData, err := os.ReadFile(jsonlPath)
	if err != nil {
		t.Fatalf("Failed to read JSONL: %v", err)
	}

	var importIssues []*types.Issue
	lines := bytes.Split(importData, []byte("\n"))
	for _, line := range lines {
		if len(line) == 0 {
			continue
		}
		var iss types.Issue
		if err := json.Unmarshal(line, &iss); err != nil {
			t.Fatalf("Failed to unmarshal: %v", err)
		}
		importIssues = append(importIssues, &iss)
	}

	result, err := importIssuesCore(ctx, dbPath, store, importIssues, opts)
	if err != nil {
		t.Fatalf("Import failed: %v", err)
	}

	// Capture stderr
	oldStderr := os.Stderr
	r, w, _ := os.Pipe()
	os.Stderr = w

	checkUncommittedChanges(jsonlPath, result)

	w.Close()
	os.Stderr = oldStderr

	var buf bytes.Buffer
	buf.ReadFrom(r)
	output := buf.String()

	// Verify NO warning when clean
	if strings.Contains(output, "Warning") || strings.Contains(output, "uncommitted") {
		t.Errorf("Expected no warning when working tree matches git HEAD, got: %s", output)
	}
}
