package utils

import (
	"database/sql"
	"testing"
	"time"
)

// ==================== Timestamp Helpers ====================

func TestNowTimestamp(t *testing.T) {
	before := time.Now()
	result := NowTimestamp()
	after := time.Now()

	// Verify format: "2006-01-02 15:04:05"
	parsed, err := time.ParseInLocation("2006-01-02 15:04:05", result, time.Local)
	if err != nil {
		t.Fatalf("NowTimestamp() returned invalid format: %q, err: %v", result, err)
	}

	// Verify it's approximately now (within a few seconds)
	if parsed.Before(before.Add(-time.Second)) || parsed.After(after.Add(time.Second)) {
		t.Errorf("NowTimestamp() = %q, not within expected time range", result)
	}
}

// ==================== Nullable Field Scanners ====================

func TestScanNullStringValue(t *testing.T) {
	tests := []struct {
		name     string
		input    sql.NullString
		expected string
	}{
		{"valid string", sql.NullString{String: "hello", Valid: true}, "hello"},
		{"valid empty string", sql.NullString{String: "", Valid: true}, ""},
		{"null value", sql.NullString{Valid: false}, ""},
		{"null with string content", sql.NullString{String: "ghost", Valid: false}, ""},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := ScanNullStringValue(tt.input)
			if result != tt.expected {
				t.Errorf("ScanNullStringValue(%+v) = %q, want %q", tt.input, result, tt.expected)
			}
		})
	}
}

// ==================== String Helpers ====================

func TestStringPtr(t *testing.T) {
	tests := []struct {
		name  string
		input string
	}{
		{"non-empty", "hello"},
		{"empty", ""},
		{"with spaces", "hello world"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := StringPtr(tt.input)
			if result == nil {
				t.Fatal("StringPtr returned nil")
			}
			if *result != tt.input {
				t.Errorf("*StringPtr(%q) = %q, want %q", tt.input, *result, tt.input)
			}
		})
	}

	t.Run("returns unique pointer", func(t *testing.T) {
		p1 := StringPtr("hello")
		p2 := StringPtr("hello")
		if p1 == p2 {
			t.Error("StringPtr should return different pointers for separate calls")
		}
	})
}

func TestContainsString(t *testing.T) {
	tests := []struct {
		name     string
		slice    []string
		item     string
		expected bool
	}{
		{"found", []string{"a", "b", "c"}, "b", true},
		{"not found", []string{"a", "b", "c"}, "d", false},
		{"empty slice", []string{}, "a", false},
		{"nil slice", nil, "a", false},
		{"empty string in slice", []string{""}, "", true},
		{"empty string not in slice", []string{"a", "b"}, "", false},
		{"case sensitive miss", []string{"Hello"}, "hello", false},
		{"first element", []string{"a", "b", "c"}, "a", true},
		{"last element", []string{"a", "b", "c"}, "c", true},
		{"single element found", []string{"only"}, "only", true},
		{"single element not found", []string{"only"}, "other", false},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := ContainsString(tt.slice, tt.item)
			if result != tt.expected {
				t.Errorf("ContainsString(%v, %q) = %v, want %v", tt.slice, tt.item, result, tt.expected)
			}
		})
	}
}

func TestContainsStringIgnoreCase(t *testing.T) {
	tests := []struct {
		name     string
		slice    []string
		item     string
		expected bool
	}{
		{"exact match", []string{"Account", "Contact"}, "Account", true},
		{"case insensitive", []string{"Account", "Contact"}, "account", true},
		{"uppercase match", []string{"account"}, "ACCOUNT", true},
		{"mixed case", []string{"MyObject"}, "myobject", true},
		{"not found", []string{"Account", "Contact"}, "Lead", false},
		{"empty slice", []string{}, "test", false},
		{"nil slice", nil, "test", false},
		{"with spaces in item", []string{"Account"}, "  Account  ", true},
		{"with spaces in slice", []string{"  Account  "}, "Account", true},
		{"empty string match", []string{""}, "", true},
		{"empty string no match", []string{"a"}, "", false},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := ContainsStringIgnoreCase(tt.slice, tt.item)
			if result != tt.expected {
				t.Errorf("ContainsStringIgnoreCase(%v, %q) = %v, want %v", tt.slice, tt.item, result, tt.expected)
			}
		})
	}
}

