package deltalake

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

func TestVacuumBasic(t *testing.T) {
	// Create a temporary directory
	tempDir := t.TempDir()
	tablePath := filepath.Join(tempDir, "test_vacuum_table")

	// Create table schema
	schema := []ColumnDefinition{
		{Name: "id", Type: "integer", Nullable: false},
		{Name: "name", Type: "string", Nullable: true},
		{Name: "value", Type: "double", Nullable: true},
	}

	// Create table
	createOptions := CreateTableOptions{
		TablePath:      tablePath,
		SaveMode:       WriteModeOverwrite,
		Columns:        schema,
		StorageOptions: map[string]string{},
	}

	table, err := CreateDeltaLakeTable(createOptions)
	if err != nil {
		t.Fatalf("Failed to create table: %v", err)
	}
	defer table.Close()

	// Write some initial data
	initialData := WriteData{
		Schema: schema,
		Data: [][]interface{}{
			{1, "Alice", 10.5},
			{2, "Bob", 20.3},
			{3, "Charlie", 30.7},
		},
	}

	table, err = table.Write(initialData, WriteModeAppend)
	if err != nil {
		t.Fatalf("Failed to write initial data: %v", err)
	}

	// Write more data to create additional versions
	moreData := WriteData{
		Schema: schema,
		Data: [][]interface{}{
			{4, "David", 40.1},
			{5, "Eve", 50.9},
		},
	}

	table, err = table.Write(moreData, WriteModeAppend)
	if err != nil {
		t.Fatalf("Failed to write more data: %v", err)
	}

	t.Run("Vacuum with dry run", func(t *testing.T) {
		// Test vacuum with dry run (should not delete anything)
		vacuum := table.Vacuum()
		if vacuum == nil {
			t.Fatal("Failed to create vacuum builder")
		}
		defer vacuum.Free()

		// Set 0 retention hours (should clean up everything except current version)
		vacuum.SetRetentionHours(0).SetDryRun(true)

		result, err := vacuum.Execute()
		if err != nil {
			t.Fatalf("Failed to execute vacuum: %v", err)
		}

		// Verify metrics
		t.Logf("Dry run metrics: %+v", result.Metrics)

		if !result.Metrics.DryRun {
			t.Error("Expected dry_run to be true")
		}

		// In dry run, files_deleted should show what would be deleted
		t.Logf("Files that would be deleted: %d", result.Metrics.TotalFilesDeleted)
	})

	t.Run("Vacuum with actual cleanup", func(t *testing.T) {
		// Test actual vacuum (will delete old files)
		vacuum := table.Vacuum()
		if vacuum == nil {
			t.Fatal("Failed to create vacuum builder")
		}
		defer vacuum.Free()

		// Set 0 retention hours and disable dry run
		vacuum.SetRetentionHours(0).SetDryRun(false)

		result, err := vacuum.Execute()
		if err != nil {
			t.Fatalf("Failed to execute vacuum: %v", err)
		}

		// Verify metrics
		t.Logf("Actual vacuum metrics: %+v", result.Metrics)

		if result.Metrics.DryRun {
			t.Error("Expected dry_run to be false")
		}

		// Update table reference
		table = result.Table

		t.Logf("Files actually deleted: %d", result.Metrics.TotalFilesDeleted)
		t.Logf("Deleted files: %v", result.Metrics.FilesDeleted)
	})

	t.Run("Vacuum with retention period", func(t *testing.T) {
		// Write more data
		additionalData := WriteData{
			Schema: schema,
			Data: [][]interface{}{
				{6, "Frank", 60.2},
			},
		}

		table, err = table.Write(additionalData, WriteModeAppend)
		if err != nil {
			t.Fatalf("Failed to write additional data: %v", err)
		}

		// Test vacuum with 24 hour retention (should not delete recent files)
		vacuum := table.Vacuum()
		if vacuum == nil {
			t.Fatal("Failed to create vacuum builder")
		}
		defer vacuum.Free()

		vacuum.SetRetentionHours(24).SetDryRun(true)

		result, err := vacuum.Execute()
		if err != nil {
			t.Fatalf("Failed to execute vacuum with retention: %v", err)
		}

		t.Logf("Vacuum with 24h retention metrics: %+v", result.Metrics)

		// With 24 hour retention, recent files should not be deleted
		if !result.Metrics.DryRun {
			t.Error("Expected dry_run to be true")
		}
	})
}

func TestVacuumError(t *testing.T) {
	t.Run("Vacuum on nil table", func(t *testing.T) {
		var table *DeltaTable
		vacuum := table.Vacuum()
		if vacuum != nil {
			t.Error("Expected nil vacuum builder for nil table")
		}
	})
}

func TestVacuumBuilderOperations(t *testing.T) {
	// Create a minimal table for testing
	tempDir := t.TempDir()
	tablePath := filepath.Join(tempDir, "test_builder_table")

	schema := []ColumnDefinition{
		{Name: "id", Type: "integer", Nullable: false},
	}

	createOptions := CreateTableOptions{
		TablePath:      tablePath,
		SaveMode:       WriteModeOverwrite,
		Columns:        schema,
		StorageOptions: map[string]string{},
	}

	table, err := CreateDeltaLakeTable(createOptions)
	if err != nil {
		t.Fatalf("Failed to create table: %v", err)
	}
	defer table.Close()

	t.Run("Builder method chaining", func(t *testing.T) {
		vacuum := table.Vacuum()
		if vacuum == nil {
			t.Fatal("Failed to create vacuum builder")
		}
		defer vacuum.Free()

		// Test method chaining
		result := vacuum.SetRetentionHours(168).SetDryRun(true)
		if result != vacuum {
			t.Error("Expected method chaining to return same builder")
		}
	})

	t.Run("Builder with different retention values", func(t *testing.T) {
		testCases := []int{0, 1, 24, 168, 720} // 0h, 1h, 1d, 1w, 1m

		for _, hours := range testCases {
			t.Run(fmt.Sprintf("retention_%dh", hours), func(t *testing.T) {
				vacuum := table.Vacuum()
				if vacuum == nil {
					t.Fatal("Failed to create vacuum builder")
				}
				defer vacuum.Free()

				vacuum.SetRetentionHours(hours).SetDryRun(true)

				result, err := vacuum.Execute()
				if err != nil {
					t.Fatalf("Failed to execute vacuum with %d hours retention: %v", hours, err)
				}

				if !result.Metrics.DryRun {
					t.Error("Expected dry_run to be true")
				}

				t.Logf("Retention %dh: would delete %d files", hours, result.Metrics.TotalFilesDeleted)
			})
		}
	})
}
