package client

import (
	"fmt"
	"testing"

	"github.com/rqlite/gorqlite"
)

// mockPanicConnection simulates what gorqlite does when WriteParameterized
// returns an empty slice: accessing [0] panics.
func simulateGorqlitePanic() (gorqlite.WriteResult, error) {
	var empty []gorqlite.WriteResult
	return empty[0], fmt.Errorf("leader not found") // panics
}

func TestSafeWriteOne_recoversPanic(t *testing.T) {
	// We can't easily create a real gorqlite.Connection that panics,
	// but we can verify our recovery wrapper works by testing the
	// recovery pattern directly.
	var recovered bool
	func() {
		defer func() {
			if r := recover(); r != nil {
				recovered = true
			}
		}()
		simulateGorqlitePanic()
	}()

	if !recovered {
		t.Fatal("expected simulateGorqlitePanic to panic, but it didn't")
	}
}

func TestSafeWriteOne_nilConnection(t *testing.T) {
	// safeWriteOne with nil connection should recover from panic, not crash.
	_, err := safeWriteOne(nil, gorqlite.ParameterizedStatement{
		Query: "INSERT INTO test (a) VALUES (?)",
		Arguments: []interface{}{"x"},
	})
	if err == nil {
		t.Fatal("expected error from nil connection, got nil")
	}
}

func TestSafeWriteOneRaw_nilConnection(t *testing.T) {
	// safeWriteOneRaw with nil connection should recover from panic, not crash.
	_, err := safeWriteOneRaw(nil, "INSERT INTO test (a) VALUES ('x')")
	if err == nil {
		t.Fatal("expected error from nil connection, got nil")
	}
}

func TestIsWriteOperation(t *testing.T) {
	d := &DatabaseClientImpl{}

	tests := []struct {
		sql    string
		isWrite bool
	}{
		{"INSERT INTO foo VALUES (1)", true},
		{"  INSERT INTO foo VALUES (1)", true},
		{"UPDATE foo SET a = 1", true},
		{"DELETE FROM foo", true},
		{"CREATE TABLE foo (a TEXT)", true},
		{"DROP TABLE foo", true},
		{"ALTER TABLE foo ADD COLUMN b TEXT", true},
		{"SELECT * FROM foo", false},
		{"  SELECT * FROM foo", false},
		{"EXPLAIN SELECT * FROM foo", false},
	}

	for _, tt := range tests {
		t.Run(tt.sql, func(t *testing.T) {
			got := d.isWriteOperation(tt.sql)
			if got != tt.isWrite {
				t.Errorf("isWriteOperation(%q) = %v, want %v", tt.sql, got, tt.isWrite)
			}
		})
	}
}
