// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package init //nolint:testpackage // testing internal validators

import (
	"errors"
	"testing"
)

func TestValidateKeyFormat_Valid(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name  string
		input string
	}{
		{"simple key", "work"},
		{"key with hyphen", "q1-goals"},
		{"key with numbers", "area2"},
		{"multiple hyphens", "my-special-area"},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			if err := validateKeyFormat(tc.input); err != nil {
				t.Errorf("validateKeyFormat(%q) = %v, want nil", tc.input, err)
			}
		})
	}
}

func TestValidateKeyFormat_Invalid(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name    string
		input   string
		wantErr error
	}{
		{"empty key", "", errKeyRequired},
		{"uppercase letters", "Work", errKeyFormat},
		{"spaces", "my area", errKeyFormat},
		{"underscores", "my_area", errKeyFormat},
		{"leading hyphen", "-work", errKeyFormat},
		{"trailing hyphen", "work-", errKeyFormat},
		{"double hyphen", "my--area", errKeyFormat},
		{"special characters", "work@home", errKeyFormat},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			if err := validateKeyFormat(tc.input); !errors.Is(err, tc.wantErr) {
				t.Errorf("validateKeyFormat(%q) = %v, want %v", tc.input, err, tc.wantErr)
			}
		})
	}
}

func TestValidateReference_Valid(t *testing.T) {
	t.Parallel()

	const (
		uuidLower = "123e4567-e89b-12d3-a456-426614174000"
		uuidArea  = "3bbf1923-64ae-4bcf-96a9-9bb86c799dab"
		uuidGoal  = "9d79e922-9ca8-4b8c-9aa5-dd98bb2492b2"
		uuidNote  = "e230ef3e-d9a5-4211-9dfb-515cc892d6e5"
	)

	tests := []struct {
		name             string
		input            string
		supportsDeepLink bool
		wantID           string
	}{
		{"valid UUID lowercase", uuidLower, false, uuidLower},
		{"valid UUID uppercase", "123E4567-E89B-12D3-A456-426614174000", false, "123E4567-E89B-12D3-A456-426614174000"},
		{"deep link area", "lunatask://areas/" + uuidArea, true, uuidArea},
		{"deep link goal", "lunatask://goals/" + uuidGoal, true, uuidGoal},
		{"deep link note", "lunatask://notes/" + uuidNote, true, uuidNote},
	}

	for _, testCase := range tests {
		t.Run(testCase.name, func(t *testing.T) {
			t.Parallel()

			id, err := validateReference(testCase.input, testCase.supportsDeepLink)
			if err != nil {
				t.Errorf("validateReference(%q, %v) = %v, want nil",
					testCase.input, testCase.supportsDeepLink, err)
			}

			if id != testCase.wantID {
				t.Errorf("validateReference(%q, %v) = %q, want %q",
					testCase.input, testCase.supportsDeepLink, id, testCase.wantID)
			}
		})
	}
}

func TestValidateReference_Invalid(t *testing.T) {
	t.Parallel()

	const validUUID = "123e4567-e89b-12d3-a456-426614174000"

	tests := []struct {
		name             string
		input            string
		supportsDeepLink bool
		wantErr          error
	}{
		{"empty reference", "", true, errRefRequired},
		{"too short", "123e4567-e89b", true, errRefFormat},
		{"random string", "not-a-uuid", true, errRefFormat},
		{"wrong characters", "123e4567-e89b-12d3-a456-42661417zzzz", false, errRefFormat},
		{"invalid scheme", "http://areas/" + validUUID, true, errRefFormat},
		{"invalid resource", "lunatask://invalid/" + validUUID, true, errRefFormat},
	}

	for _, testCase := range tests {
		t.Run(testCase.name, func(t *testing.T) {
			t.Parallel()

			_, err := validateReference(testCase.input, testCase.supportsDeepLink)
			if !errors.Is(err, testCase.wantErr) {
				t.Errorf("validateReference(%q, %v) = %v, want %v",
					testCase.input, testCase.supportsDeepLink, err, testCase.wantErr)
			}
		})
	}
}

func TestParseEditIndex_Valid(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name    string
		input   string
		wantIdx int
	}{
		{"index 0", "edit:0", 0},
		{"index 5", "edit:5", 5},
		{"large index", "edit:999", 999},
		{"negative index", "edit:-1", -1},
	}

	for _, testCase := range tests {
		t.Run(testCase.name, func(t *testing.T) {
			t.Parallel()

			idx, valid := parseEditIndex(testCase.input)
			if !valid {
				t.Errorf("parseEditIndex(%q) valid = false, want true", testCase.input)
			}

			if idx != testCase.wantIdx {
				t.Errorf("parseEditIndex(%q) idx = %d, want %d", testCase.input, idx, testCase.wantIdx)
			}
		})
	}
}

func TestParseEditIndex_Invalid(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name  string
		input string
	}{
		{"back choice", "back"},
		{"add choice", "add"},
		{"done choice", "done"},
		{"empty prefix", "edit:"},
		{"non-numeric", "edit:abc"},
		{"empty string", ""},
	}

	for _, testCase := range tests {
		t.Run(testCase.name, func(t *testing.T) {
			t.Parallel()

			_, valid := parseEditIndex(testCase.input)
			if valid {
				t.Errorf("parseEditIndex(%q) valid = true, want false", testCase.input)
			}
		})
	}
}

func TestTitleCase(t *testing.T) {
	t.Parallel()

	tests := []struct {
		input string
		want  string
	}{
		{"area", "Area"},
		{"goal", "Goal"},
		{"notebook", "Notebook"},
		{"habit", "Habit"},
		{"a", "A"},
		{"", ""},
		{"already Capitalized", "Already Capitalized"},
	}

	for _, tc := range tests {
		t.Run(tc.input, func(t *testing.T) {
			t.Parallel()

			if got := titleCase(tc.input); got != tc.want {
				t.Errorf("titleCase(%q) = %q, want %q", tc.input, got, tc.want)
			}
		})
	}
}
