package utils

import (
	"testing"

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

// TestNormalizeTags tests tag display normalization
func TestNormalizeTags(t *testing.T) {
	tests := []struct {
		name     string
		input    []string
		expected []string
	}{
		{
			name:     "empty array",
			input:    []string{},
			expected: []string{},
		},
		{
			name:     "nil input",
			input:    nil,
			expected: []string{},
		},
		{
			name:     "single tag",
			input:    []string{"  science fiction  "},
			expected: []string{"Science Fiction"},
		},
		{
			name:     "multiple tags",
			input:    []string{"fiction", "adventure"},
			expected: []string{"Fiction", "Adventure"},
		},
		{
			name:     "multi-word tag",
			input:    []string{"  science fiction  "},
			expected: []string{"Science Fiction"},
		},
		{
			name:     "hyphenated tag",
			input:    []string{"non-fiction"},
			expected: []string{"Non-Fiction"},
		},
		{
			name:     "mixed case",
			input:    []string{"FICTION", "fiction", "Fiction"},
			expected: []string{"Fiction"},
		},
		{
			name:     "case-insensitive dedup",
			input:    []string{"fiction", "FICTION", "Fiction"},
			expected: []string{"Fiction"},
		},
		{
			name:     "remove empty strings",
			input:    []string{"fiction", "", "adventure", "  "},
			expected: []string{"Fiction", "Adventure"},
		},
		{
			name:     "whitespace trimming",
			input:    []string{"  fiction  ", "\tadventure\t"},
			expected: []string{"Fiction", "Adventure"},
		},
		{
			name:     "preserves punctuation",
			input:    []string{"science-fiction", "O'Reilly"},
			expected: []string{"Science-Fiction", "O'Reilly"},
		},
		{
			name:     "complex real-world example",
			input:    []string{"  science fiction  ", "FICTION", "non-fiction", "", "  "},
			expected: []string{"Science Fiction", "Fiction", "Non-Fiction"},
		},
		{
			name:     "prefer punctuation - hyphenated tag",
			input:    []string{"science fiction", "science-fiction", "Science Fiction"},
			expected: []string{"Science-Fiction"},
		},
		{
			name:     "prefer punctuation - apostrophe tag",
			input:    []string{"OReilly Media", "oreilly media", "O'Reilly Media"},
			expected: []string{"O'Reilly Media"},
		},
		{
			name:     "prefer punctuation - mixed",
			input:    []string{"nonfiction", "non-fiction", "NONFICTION"},
			expected: []string{"Non-Fiction"},
		},
		{
			name:     "prefer first punctuation when multiple have punctuation",
			input:    []string{"science-fiction", "science fiction", "Science-Fiction"},
			expected: []string{"Science-Fiction"},
		},
	}

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

// TestNormalizeTagsSearch tests tag search normalization
func TestNormalizeTagsSearch(t *testing.T) {
	tests := []struct {
		name     string
		input    []string
		expected []string
	}{
		{
			name:     "empty array",
			input:    []string{},
			expected: []string{},
		},
		{
			name:     "nil input",
			input:    nil,
			expected: []string{},
		},
		{
			name:     "single tag",
			input:    []string{"  Science Fiction  "},
			expected: []string{"science fiction"},
		},
		{
			name:     "lowercase",
			input:    []string{"SCIENCE FICTION"},
			expected: []string{"science fiction"},
		},
		{
			name:     "remove punctuation",
			input:    []string{"science-fiction"},
			expected: []string{"science fiction"},
		},
		{
			name:     "remove period",
			input:    []string{"ACME CORP."},
			expected: []string{"acme corp"},
		},
		{
			name:     "remove multiple punctuation",
			input:    []string{"O'Reilly Media!"},
			expected: []string{"oreilly media"},
		},
		{
			name:     "case-insensitive dedup",
			input:    []string{"science fiction", "SCIENCE FICTION", "Science Fiction"},
			expected: []string{"science fiction"},
		},
		{
			name:     "remove empty after punctuation removal",
			input:    []string{"..."},
			expected: []string{},
		},
		{
			name:     "complex example",
			input:    []string{"  Science-Fiction  ", "FICTION", "", "  "},
			expected: []string{"science fiction", "fiction"},
		},
	}

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

// TestNormalizeContributors tests contributor display normalization
func TestNormalizeContributors(t *testing.T) {
	tests := []struct {
		name     string
		input    []string
		expected []string
	}{
		{
			name:     "empty array",
			input:    []string{},
			expected: []string{},
		},
		{
			name:     "nil input",
			input:    nil,
			expected: []string{},
		},
		{
			name:     "single contributor",
			input:    []string{"  ACME CORP  "},
			expected: []string{"ACME CORP"},
		},
		{
			name:     "preserve case - CAPSLOCK",
			input:    []string{"ACME CORP"},
			expected: []string{"ACME CORP"},
		},
		{
			name:     "preserve case - Title Case",
			input:    []string{"Acme Corp"},
			expected: []string{"Acme Corp"},
		},
		{
			name:     "preserve case - lowercase",
			input:    []string{"acme corp"},
			expected: []string{"acme corp"},
		},
		{
			name:     "preserve punctuation - period",
			input:    []string{"ACME CORP."},
			expected: []string{"ACME CORP."},
		},
		{
			name:     "preserve punctuation - apostrophe",
			input:    []string{"O'Reilly Media"},
			expected: []string{"O'Reilly Media"},
		},
		{
			name:     "case-insensitive dedup - different case",
			input:    []string{"ACME CORP", "Acme Corp", "acme corp"},
			expected: []string{"ACME CORP"},
		},
		{
			name:     "case-insensitive dedup - with punctuation",
			input:    []string{"ACME CORP.", "Acme Corp", "acme corp"},
			expected: []string{"ACME CORP."},
		},
		{
			name:     "trim whitespace",
			input:    []string{"  ACME CORP  ", "\tAcme\t"},
			expected: []string{"ACME CORP", "Acme"},
		},
		{
			name:     "remove empty strings",
			input:    []string{"ACME CORP", "", "Acme Corp", "  "},
			expected: []string{"ACME CORP"},
		},
		{
			name:     "complex real-world example",
			input:    []string{"  ACME CORP.  ", "Acme Corp", "acme corp", "  "},
			expected: []string{"ACME CORP."},
		},
		{
			name:     "prefer punctuation - period at end",
			input:    []string{"acme corp", "ACME CORP.", "Acme Corp"},
			expected: []string{"ACME CORP."},
		},
		{
			name:     "prefer punctuation - apostrophe",
			input:    []string{"OReilly Media", "oreilly media", "O'Reilly Media"},
			expected: []string{"O'Reilly Media"},
		},
		{
			name:     "prefer punctuation - mixed",
			input:    []string{"ACME CORP", "Acme Corp", "acme corp."},
			expected: []string{"acme corp."},
		},
		{
			name:     "prefer first punctuation when multiple have punctuation",
			input:    []string{"ACME CORP!", "ACME CORP.", "Acme Corp"},
			expected: []string{"ACME CORP!"},
		},
	}

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

// TestNormalizeContributorsSearch tests contributor search normalization
func TestNormalizeContributorsSearch(t *testing.T) {
	tests := []struct {
		name     string
		input    []string
		expected []string
	}{
		{
			name:     "empty array",
			input:    []string{},
			expected: []string{},
		},
		{
			name:     "nil input",
			input:    nil,
			expected: []string{},
		},
		{
			name:     "single contributor",
			input:    []string{"  ACME CORP.  "},
			expected: []string{"acme corp"},
		},
		{
			name:     "lowercase",
			input:    []string{"ACME CORP"},
			expected: []string{"acme corp"},
		},
		{
			name:     "remove punctuation - period",
			input:    []string{"ACME CORP."},
			expected: []string{"acme corp"},
		},
		{
			name:     "remove punctuation - apostrophe",
			input:    []string{"O'Reilly Media"},
			expected: []string{"oreilly media"},
		},
		{
			name:     "case-insensitive dedup",
			input:    []string{"ACME CORP", "acme corp", "Acme Corp"},
			expected: []string{"acme corp"},
		},
		{
			name:     "case-insensitive dedup with punctuation",
			input:    []string{"ACME CORP.", "Acme Corp", "acme corp"},
			expected: []string{"acme corp"},
		},
		{
			name:     "remove empty after punctuation removal",
			input:    []string{"..."},
			expected: []string{},
		},
		{
			name:     "complex example",
			input:    []string{"  ACME CORP.  ", "Acme Corp", "acme corp", "  "},
			expected: []string{"acme corp"},
		},
	}

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

// TestTitlecase tests titlecase helper function
func TestTitlecase(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		expected string
	}{
		{
			name:     "simple word",
			input:    "science",
			expected: "Science",
		},
		{
			name:     "multi-word",
			input:    "science fiction",
			expected: "Science Fiction",
		},
		{
			name:     "hyphenated",
			input:    "non-fiction",
			expected: "Non-Fiction",
		},
		{
			name:     "already capitalized",
			input:    "Science Fiction",
			expected: "Science Fiction",
		},
		{
			name:     "all caps",
			input:    "SCIENCE FICTION",
			expected: "Science Fiction",
		},
		{
			name:     "all lowercase",
			input:    "science fiction",
			expected: "Science Fiction",
		},
		{
			name:     "apostrophe",
			input:    "o'reilly media",
			expected: "O'Reilly Media",
		},
	}

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

// TestRemovePunctuation tests punctuation removal
func TestRemovePunctuation(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		expected string
	}{
		{
			name:     "no punctuation",
			input:    "acme corp",
			expected: "acme corp",
		},
		{
			name:     "period",
			input:    "ACME CORP.",
			expected: "ACME CORP",
		},
		{
			name:     "apostrophe",
			input:    "O'Reilly",
			expected: "OReilly",
		},
		{
			name:     "multiple punctuation",
			input:    "science-fiction!",
			expected: "science fiction",
		},
		{
			name:     "only punctuation",
			input:    "...",
			expected: "",
		},
		{
			name:     "mixed content",
			input:    "O'Reilly Media!",
			expected: "OReilly Media",
		},
	}

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

// TestJoinTags tests tag joining
func TestJoinTags(t *testing.T) {
	tests := []struct {
		name     string
		input    []string
		expected string
	}{
		{
			name:     "empty array",
			input:    []string{},
			expected: "",
		},
		{
			name:     "single tag",
			input:    []string{"fiction"},
			expected: "fiction",
		},
		{
			name:     "multiple tags",
			input:    []string{"fiction", "adventure"},
			expected: "fiction, adventure",
		},
	}

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

// TestSplitTags tests tag splitting and normalization
func TestSplitTags(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		expected []string
	}{
		{
			name:     "empty string",
			input:    "",
			expected: []string{},
		},
		{
			name:     "single tag",
			input:    "fiction",
			expected: []string{"Fiction"},
		},
		{
			name:     "multiple tags comma separated",
			input:    "fiction, adventure",
			expected: []string{"Fiction", "Adventure"},
		},
		{
			name:     "with spaces",
			input:    "fiction,adventure",
			expected: []string{"Fiction", "Adventure"},
		},
		{
			name:     "with extra spaces",
			input:    " fiction , adventure ",
			expected: []string{"Fiction", "Adventure"},
		},
		{
			name:     "deduplicates",
			input:    "fiction, FICTION, Fiction",
			expected: []string{"Fiction"},
		},
	}

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