//go:build integration
// +build integration

package main

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

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

func TestReadIssueIDsFromFile(t *testing.T) {
	tmpDir, err := os.MkdirTemp("", "bd-test-delete-*")
	if err != nil {
		t.Fatalf("Failed to create temp dir: %v", err)
	}
	defer os.RemoveAll(tmpDir)

	t.Run("read valid IDs from file", func(t *testing.T) {
		testFile := filepath.Join(tmpDir, "ids.txt")
		content := "bd-1\nbd-2\nbd-3\n"
		if err := os.WriteFile(testFile, []byte(content), 0644); err != nil {
			t.Fatalf("Failed to write test file: %v", err)
		}

		ids, err := readIssueIDsFromFile(testFile)
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}

		if len(ids) != 3 {
			t.Errorf("Expected 3 IDs, got %d", len(ids))
		}

		expected := []string{"bd-1", "bd-2", "bd-3"}
		for i, id := range ids {
			if id != expected[i] {
				t.Errorf("Expected ID %s at position %d, got %s", expected[i], i, id)
			}
		}
	})

	t.Run("skip empty lines and comments", func(t *testing.T) {
		testFile := filepath.Join(tmpDir, "ids_with_comments.txt")
		content := "bd-1\n\n# This is a comment\nbd-2\n  \nbd-3\n"
		if err := os.WriteFile(testFile, []byte(content), 0644); err != nil {
			t.Fatalf("Failed to write test file: %v", err)
		}

		ids, err := readIssueIDsFromFile(testFile)
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}

		if len(ids) != 3 {
			t.Errorf("Expected 3 IDs (skipping comments/empty), got %d", len(ids))
		}
	})

	t.Run("handle non-existent file", func(t *testing.T) {
		_, err := readIssueIDsFromFile(filepath.Join(tmpDir, "nonexistent.txt"))
		if err == nil {
			t.Error("Expected error for non-existent file")
		}
	})
}

func TestUniqueStrings(t *testing.T) {
	t.Run("remove duplicates", func(t *testing.T) {
		input := []string{"a", "b", "a", "c", "b", "d"}
		result := uniqueStrings(input)

		if len(result) != 4 {
			t.Errorf("Expected 4 unique strings, got %d", len(result))
		}

		// Verify all unique values are present
		seen := make(map[string]bool)
		for _, s := range result {
			if seen[s] {
				t.Errorf("Duplicate found in result: %s", s)
			}
			seen[s] = true
		}
	})

	t.Run("handle empty input", func(t *testing.T) {
		result := uniqueStrings([]string{})
		if len(result) != 0 {
			t.Errorf("Expected empty result, got %d items", len(result))
		}
	})

	t.Run("handle all unique", func(t *testing.T) {
		input := []string{"a", "b", "c"}
		result := uniqueStrings(input)

		if len(result) != 3 {
			t.Errorf("Expected 3 items, got %d", len(result))
		}
	})
}

func TestBulkDeleteNoResurrection(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping integration test in short mode")
	}

	tmpDir := t.TempDir()
	beadsDir := filepath.Join(tmpDir, ".beads")
	testDB := filepath.Join(beadsDir, "beads.db")
	jsonlPath := filepath.Join(beadsDir, "issues.jsonl")

	testGitInit(t, tmpDir)

	s := newTestStore(t, testDB)
	ctx := context.Background()

	totalIssues := 20
	toDeleteCount := 10
	var toDelete []string

	for i := 1; i <= totalIssues; i++ {
		issue := &types.Issue{
			Title:       "Issue " + string(rune('A'+i-1)),
			Description: "Test issue",
			Status:      types.StatusOpen,
			Priority:    2,
			IssueType:   "task",
		}
		if err := s.CreateIssue(ctx, issue, "test"); err != nil {
			t.Fatalf("Failed to create issue %d: %v", i, err)
		}
		if i <= toDeleteCount {
			toDelete = append(toDelete, issue.ID)
		}
	}

	exportToJSONLTest(t, s, jsonlPath)
	testGitCommit(t, tmpDir, jsonlPath, "Add issues")

	oldStore := store
	oldDbPath := dbPath
	oldAutoImportEnabled := autoImportEnabled
	defer func() {
		store = oldStore
		dbPath = oldDbPath
		autoImportEnabled = oldAutoImportEnabled
	}()

	store = s
	dbPath = testDB
	autoImportEnabled = true

	result, err := s.DeleteIssues(ctx, toDelete, false, true, false)
	if err != nil {
		t.Fatalf("DeleteIssues failed: %v", err)
	}

	if result.DeletedCount != toDeleteCount {
		t.Errorf("Expected %d deletions, got %d", toDeleteCount, result.DeletedCount)
	}

	for _, id := range toDelete {
		if err := removeIssueFromJSONL(id); err != nil {
			t.Fatalf("removeIssueFromJSONL failed for %s: %v", id, err)
		}
	}

	stats, err := s.GetStatistics(ctx)
	if err != nil {
		t.Fatalf("GetStatistics failed: %v", err)
	}

	expectedRemaining := totalIssues - toDeleteCount
	if stats.TotalIssues != expectedRemaining {
		t.Errorf("After delete: expected %d issues in DB, got %d", expectedRemaining, stats.TotalIssues)
	}

	jsonlIssues := countJSONLIssuesTest(t, jsonlPath)
	if jsonlIssues != expectedRemaining {
		t.Errorf("After delete: expected %d issues in JSONL, got %d", expectedRemaining, jsonlIssues)
	}

	for _, id := range toDelete {
		issue, err := s.GetIssue(ctx, id)
		if err != nil {
			t.Fatalf("GetIssue failed for %s: %v", id, err)
		}
		if issue != nil {
			t.Errorf("Deleted issue %s was resurrected!", id)
		}
	}
}

func exportToJSONLTest(t *testing.T, s *sqlite.SQLiteStorage, jsonlPath string) {
	t.Helper()
	ctx := context.Background()
	issues, err := s.SearchIssues(ctx, "", types.IssueFilter{})
	if err != nil {
		t.Fatalf("SearchIssues failed: %v", err)
	}

	if err := os.MkdirAll(filepath.Dir(jsonlPath), 0755); err != nil {
		t.Fatalf("Failed to create JSONL dir: %v", err)
	}

	f, err := os.Create(jsonlPath)
	if err != nil {
		t.Fatalf("Failed to create JSONL: %v", err)
	}
	defer f.Close()

	enc := json.NewEncoder(f)
	for _, iss := range issues {
		if err := enc.Encode(iss); err != nil {
			t.Fatalf("Failed to encode issue: %v", err)
		}
	}
}

func testGitInit(t *testing.T, dir string) {
	t.Helper()
	testGitCmd(t, dir, "init")
	testGitCmd(t, dir, "config", "user.email", "test@example.com")
	testGitCmd(t, dir, "config", "user.name", "Test User")
}

func testGitCommit(t *testing.T, dir, file, msg string) {
	t.Helper()
	testGitCmd(t, dir, "add", file)
	testGitCmd(t, dir, "commit", "-m", msg)
}

func testGitCmd(t *testing.T, dir string, args ...string) {
	t.Helper()
	cmd := exec.Command("git", args...)
	cmd.Dir = dir
	if output, err := cmd.CombinedOutput(); err != nil {
		t.Fatalf("git %v failed: %v\nOutput: %s", args, err, output)
	}
}

func countJSONLIssuesTest(t *testing.T, jsonlPath string) int {
	t.Helper()
	data, err := os.ReadFile(jsonlPath)
	if err != nil {
		if os.IsNotExist(err) {
			return 0
		}
		t.Fatalf("Failed to read JSONL: %v", err)
	}

	count := 0
	scanner := bufio.NewScanner(bytes.NewReader(data))
	for scanner.Scan() {
		line := scanner.Text()
		if len(bytes.TrimSpace([]byte(line))) > 0 {
			count++
		}
	}
	if err := scanner.Err(); err != nil {
		t.Fatalf("Scanner error: %v", err)
	}
	return count
}
