package utils

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestNormalizeISBN_ValidISBNs(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		expected string
	}{
		{
			name:     "ISBN-10 with hyphens",
			input:    "0-306-40615-2",
			expected: "0306406152",
		},
		{
			name:     "ISBN-13 with hyphens",
			input:    "978-0-306-40615-7",
			expected: "9780306406157",
		},
		{
			name:     "ISBN-10 with spaces",
			input:    "0 306 40615 2",
			expected: "0306406152",
		},
		{
			name:     "ISBN-13 with spaces",
			input:    "978 0 306 40615 7",
			expected: "9780306406157",
		},
		{
			name:     "ISBN-10 with hyphens and spaces",
			input:    "0-306-40615 2",
			expected: "0306406152",
		},
		{
			name:     "ISBN-13 with hyphens and spaces",
			input:    "978-0-306 40615-7",
			expected: "9780306406157",
		},
		{
			name:     "ISBN-10 clean",
			input:    "0306406152",
			expected: "0306406152",
		},
		{
			name:     "ISBN-13 clean",
			input:    "9780306406157",
			expected: "9780306406157",
		},
		{
			name:     "ISBN-10 with X",
			input:    "0-8044-2957-X",
			expected: "080442957X",
		},
		{
			name:     "ISBN-10 with X and hyphens",
			input:    "0-8044-2957-X",
			expected: "080442957X",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := NormalizeISBNSafe(tt.input)
			assert.Equal(t, tt.expected, result)
		})
	}
}

func TestNormalizeISBN_EdgeCases(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		expected string
	}{
		{
			name:     "empty string",
			input:    "",
			expected: "",
		},
		{
			name:     "only hyphens",
			input:    "---",
			expected: "",
		},
		{
			name:     "only spaces",
			input:    "   ",
			expected: "",
		},
		{
			name:     "mixed hyphens and spaces",
			input:    "- - -",
			expected: "",
		},
		{
			name:     "multiple consecutive hyphens",
			input:    "0--306--40615--2",
			expected: "0306406152",
		},
		{
			name:     "multiple consecutive spaces",
			input:    "0  306  40615  2",
			expected: "0306406152",
		},
		{
			name:     "tabs and newlines (treated as spaces)",
			input:    "0\t306\n40615\r2",
			expected: "0306406152",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := NormalizeISBNSafe(tt.input)
			assert.Equal(t, tt.expected, result)
		})
	}
}

func TestNormalizeISBN_SpecialCharacters(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		expected string
	}{
		{
			name:     "mixed dots and hyphens (hyphens removed, dots preserved)",
			input:    "978-0.306-40615.7",
			expected: "9780.30640615.7",
		},
		{
			name:     "multiple spaces between groups",
			input:    "978  0  306  40615  7",
			expected: "9780306406157",
		},
		{
			name:     "mixed hyphens and spaces",
			input:    "978-0 306-40615 7",
			expected: "9780306406157",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := NormalizeISBNSafe(tt.input)
			assert.Equal(t, tt.expected, result)
		})
	}
}

func TestNormalizeISBN_RealWorldExamples(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		expected string
	}{
		{
			name:     "real book ISBN-10",
			input:    "0-596-00965-X",
			expected: "059600965X",
		},
		{
			name:     "real book ISBN-13",
			input:    "978-0-596-00965-2",
			expected: "9780596009652",
		},
		{
			name:     "another real ISBN-10",
			input:    "1-4028-9462-7",
			expected: "1402894627",
		},
		{
			name:     "another real ISBN-13",
			input:    "978-1-4028-9462-6",
			expected: "9781402894626",
		},
		{
			name:     "popular programming book",
			input:    "978-0-13-595705-9",
			expected: "9780135957059",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := NormalizeISBNSafe(tt.input)
			assert.Equal(t, tt.expected, result)
		})
	}
}

func TestNormalizeISBN_DoesNotModifyValidISBNs(t *testing.T) {
	validISBNs := []string{
		"0306406152",
		"9780306406157",
		"080442957X",
		"1234567890123",
	}

	for _, isbn := range validISBNs {
		t.Run(isbn, func(t *testing.T) {
			result := NormalizeISBNSafe(isbn)
			assert.Equal(t, isbn, result, "Valid ISBN should not be modified")
		})
	}
}

func TestNormalizeISBN_PreservesX(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		expected string
	}{
		{
			name:     "X at end",
			input:    "0-8044-2957-X",
			expected: "080442957X",
		},
		{
			name:     "lowercase x",
			input:    "0-8044-2957-x",
			expected: "080442957x",
		},
		{
			name:     "X in middle (invalid but preserved)",
			input:    "0-8044-X-2957",
			expected: "08044X2957",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := NormalizeISBNSafe(tt.input)
			assert.Equal(t, tt.expected, result)
		})
	}
}
