//go:build integration
// +build integration

package importer

import (
	"context"
	"path/filepath"
	"testing"
	"time"

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

func TestImportWithExternalRef(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping slow import test in short mode")
	}
	ctx := context.Background()
	tmpDir := t.TempDir()
	dbPath := filepath.Join(tmpDir, "test.db")

	// Create database
	store, err := sqlite.New(context.Background(), dbPath)
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer store.Close()

	// Set prefix
	if err := store.SetConfig(ctx, "issue_prefix", "bd"); err != nil {
		t.Fatalf("Failed to set prefix: %v", err)
	}

	// Create initial issue with external_ref
	externalRef := "JIRA-100"
	initial := &types.Issue{
		ID:          "bd-test-1",
		Title:       "Initial title",
		Description: "Initial description",
		Status:      types.StatusOpen,
		Priority:    1,
		IssueType:   types.TypeBug,
		ExternalRef: &externalRef,
		CreatedAt:   time.Now().Add(-2 * time.Hour),
		UpdatedAt:   time.Now().Add(-2 * time.Hour),
	}

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

	// Import updated issue with same external_ref but different content
	updated := &types.Issue{
		ID:          "bd-test-1", // Same ID
		Title:       "Updated title from Jira",
		Description: "Updated description from Jira",
		Status:      types.StatusInProgress,
		Priority:    2,
		IssueType:   types.TypeBug,
		ExternalRef: &externalRef, // Same external_ref
		CreatedAt:   initial.CreatedAt,
		UpdatedAt:   time.Now(), // Newer timestamp
	}

	opts := Options{
		DryRun:               false,
		SkipUpdate:           false,
		SkipPrefixValidation: true,
	}

	result, err := ImportIssues(ctx, dbPath, store, []*types.Issue{updated}, opts)
	if err != nil {
		t.Fatalf("ImportIssues failed: %v", err)
	}

	// Should have updated 1 issue
	if result.Updated != 1 {
		t.Errorf("Expected 1 updated issue, got %d", result.Updated)
	}

	if result.Created != 0 {
		t.Errorf("Expected 0 created issues, got %d", result.Created)
	}

	// Verify the update
	issue, err := store.GetIssue(ctx, "bd-test-1")
	if err != nil {
		t.Fatalf("Failed to get issue: %v", err)
	}

	if issue.Title != "Updated title from Jira" {
		t.Errorf("Expected title 'Updated title from Jira', got '%s'", issue.Title)
	}

	if issue.Status != types.StatusInProgress {
		t.Errorf("Expected status in_progress, got %s", issue.Status)
	}
}

func TestImportWithExternalRefDifferentID(t *testing.T) {
	ctx := context.Background()
	tmpDir := t.TempDir()
	dbPath := filepath.Join(tmpDir, "test.db")

	// Create database
	store, err := sqlite.New(context.Background(), dbPath)
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer store.Close()

	// Set prefix
	if err := store.SetConfig(ctx, "issue_prefix", "bd"); err != nil {
		t.Fatalf("Failed to set prefix: %v", err)
	}

	// Create initial issue with external_ref
	externalRef := "GH-200"
	initial := &types.Issue{
		ID:          "bd-old-id",
		Title:       "Initial title",
		Description: "Initial description",
		Status:      types.StatusOpen,
		Priority:    1,
		IssueType:   types.TypeFeature,
		ExternalRef: &externalRef,
		CreatedAt:   time.Now().Add(-2 * time.Hour),
		UpdatedAt:   time.Now().Add(-2 * time.Hour),
	}

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

	// Import issue with same external_ref but DIFFERENT ID
	// This simulates re-syncing from GitHub where ID changed
	updated := &types.Issue{
		ID:          "bd-new-id", // Different ID
		Title:       "Updated title from GitHub",
		Description: "Updated description from GitHub",
		Status:      types.StatusInProgress,
		Priority:    2,
		IssueType:   types.TypeFeature,
		ExternalRef: &externalRef, // Same external_ref
		CreatedAt:   initial.CreatedAt,
		UpdatedAt:   time.Now(), // Newer timestamp
	}

	opts := Options{
		DryRun:               false,
		SkipUpdate:           false,
		SkipPrefixValidation: true,
	}

	result, err := ImportIssues(ctx, dbPath, store, []*types.Issue{updated}, opts)
	if err != nil {
		t.Fatalf("ImportIssues failed: %v", err)
	}

	// Should have updated the existing issue (matched by external_ref)
	if result.Updated != 1 {
		t.Errorf("Expected 1 updated issue, got %d", result.Updated)
	}

	// Verify the old ID was updated (not deleted/recreated)
	oldIssue, err := store.GetIssue(ctx, "bd-old-id")
	if err != nil {
		t.Fatalf("Failed to get issue by old ID: %v", err)
	}

	if oldIssue == nil {
		t.Fatal("Expected old ID to still exist and be updated")
	}

	if oldIssue.Title != "Updated title from GitHub" {
		t.Errorf("Expected title 'Updated title from GitHub', got '%s'", oldIssue.Title)
	}

	// The new ID should NOT exist (we updated the existing one)
	newIssue, err := store.GetIssue(ctx, "bd-new-id")
	if err != nil {
		t.Fatalf("Failed to check for new ID: %v", err)
	}

	if newIssue != nil {
		t.Error("Expected new ID to NOT be created, but it exists")
	}
}

func TestImportLocalIssueNotOverwrittenByExternalRef(t *testing.T) {
	ctx := context.Background()
	tmpDir := t.TempDir()
	dbPath := filepath.Join(tmpDir, "test.db")

	// Create database
	store, err := sqlite.New(context.Background(), dbPath)
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer store.Close()

	// Set prefix
	if err := store.SetConfig(ctx, "issue_prefix", "bd"); err != nil {
		t.Fatalf("Failed to set prefix: %v", err)
	}

	// Create local issue WITHOUT external_ref
	local := &types.Issue{
		ID:          "bd-local-1",
		Title:       "Local task",
		Description: "Created locally",
		Status:      types.StatusOpen,
		Priority:    1,
		IssueType:   types.TypeTask,
		// No ExternalRef
		CreatedAt: time.Now().Add(-2 * time.Hour),
		UpdatedAt: time.Now().Add(-2 * time.Hour),
	}

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

	// Import external issue with external_ref but different ID
	externalRef := "JIRA-300"
	external := &types.Issue{
		ID:          "bd-external-1",
		Title:       "External issue",
		Description: "From Jira",
		Status:      types.StatusOpen,
		Priority:    1,
		IssueType:   types.TypeBug,
		ExternalRef: &externalRef,
		CreatedAt:   time.Now().Add(-1 * time.Hour),
		UpdatedAt:   time.Now().Add(-1 * time.Hour),
	}

	opts := Options{
		DryRun:               false,
		SkipUpdate:           false,
		SkipPrefixValidation: true,
	}

	result, err := ImportIssues(ctx, dbPath, store, []*types.Issue{external}, opts)
	if err != nil {
		t.Fatalf("ImportIssues failed: %v", err)
	}

	// Should create new issue (not overwrite local one)
	if result.Created != 1 {
		t.Errorf("Expected 1 created issue, got %d", result.Created)
	}

	// Verify local issue still exists unchanged
	localIssue, err := store.GetIssue(ctx, "bd-local-1")
	if err != nil {
		t.Fatalf("Failed to get local issue: %v", err)
	}

	if localIssue == nil {
		t.Fatal("Local issue was deleted!")
	}

	if localIssue.Title != "Local task" {
		t.Errorf("Local issue was modified! Title: %s", localIssue.Title)
	}

	if localIssue.ExternalRef != nil {
		t.Error("Local issue should not have external_ref")
	}

	// Verify external issue was created
	externalIssue, err := store.GetIssue(ctx, "bd-external-1")
	if err != nil {
		t.Fatalf("Failed to get external issue: %v", err)
	}

	if externalIssue == nil {
		t.Fatal("External issue was not created")
	}

	if externalIssue.ExternalRef == nil || *externalIssue.ExternalRef != externalRef {
		t.Error("External issue missing external_ref")
	}
}

func TestImportExternalRefTimestampCheck(t *testing.T) {
	ctx := context.Background()
	tmpDir := t.TempDir()
	dbPath := filepath.Join(tmpDir, "test.db")

	// Create database
	store, err := sqlite.New(context.Background(), dbPath)
	if err != nil {
		t.Fatalf("Failed to create database: %v", err)
	}
	defer store.Close()

	// Set prefix
	if err := store.SetConfig(ctx, "issue_prefix", "bd"); err != nil {
		t.Fatalf("Failed to set prefix: %v", err)
	}

	// Create issue with external_ref and recent timestamp
	externalRef := "LINEAR-400"
	recent := &types.Issue{
		ID:          "bd-test-1",
		Title:       "Recent version",
		Description: "Most recent",
		Status:      types.StatusInProgress,
		Priority:    1,
		IssueType:   types.TypeBug,
		ExternalRef: &externalRef,
		CreatedAt:   time.Now().Add(-1 * time.Hour),
		UpdatedAt:   time.Now(), // Recent
	}

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

	// Try to import older version with same external_ref
	older := &types.Issue{
		ID:          "bd-test-1",
		Title:       "Older version",
		Description: "Older",
		Status:      types.StatusOpen,
		Priority:    2,
		IssueType:   types.TypeBug,
		ExternalRef: &externalRef,
		CreatedAt:   time.Now().Add(-2 * time.Hour),
		UpdatedAt:   time.Now().Add(-2 * time.Hour), // Older
	}

	opts := Options{
		DryRun:               false,
		SkipUpdate:           false,
		SkipPrefixValidation: true,
	}

	result, err := ImportIssues(ctx, dbPath, store, []*types.Issue{older}, opts)
	if err != nil {
		t.Fatalf("ImportIssues failed: %v", err)
	}

	// Should NOT update (incoming is older)
	if result.Updated != 0 {
		t.Errorf("Expected 0 updated issues (timestamp check), got %d", result.Updated)
	}

	if result.Unchanged != 1 {
		t.Errorf("Expected 1 unchanged issue, got %d", result.Unchanged)
	}

	// Verify the issue was not changed
	issue, err := store.GetIssue(ctx, "bd-test-1")
	if err != nil {
		t.Fatalf("Failed to get issue: %v", err)
	}

	if issue.Title != "Recent version" {
		t.Errorf("Issue was updated when it shouldn't be! Title: %s", issue.Title)
	}

	if issue.Status != types.StatusInProgress {
		t.Errorf("Issue status changed! Got %s", issue.Status)
	}
}
