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

package deeplink_test

import (
	"errors"
	"testing"

	"git.secluded.site/lune/internal/deeplink"
)

func TestParseID_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"
	)

	tests := []struct {
		name   string
		input  string
		wantID string
	}{
		{"UUID lowercase", uuidLower, uuidLower},
		{"UUID uppercase", "123E4567-E89B-12D3-A456-426614174000", uuidLower},
		{"deep link areas", "lunatask://areas/" + uuidArea, uuidArea},
		{"deep link goals", "lunatask://goals/" + uuidGoal, uuidGoal},
		{"deep link tasks", "lunatask://tasks/" + uuidArea, uuidArea},
		{"deep link notes", "lunatask://notes/" + uuidArea, uuidArea},
		{"deep link people", "lunatask://people/" + uuidArea, uuidArea},
		{"deep link notebooks", "lunatask://notebooks/" + uuidArea, uuidArea},
		{"with whitespace", "  " + uuidLower + "  ", uuidLower},
	}

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

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

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

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

	tests := []struct {
		name    string
		input   string
		wantErr error
	}{
		{"empty", "", deeplink.ErrInvalidReference},
		{"random text", "not-a-uuid", deeplink.ErrInvalidReference},
		{"invalid UUID", "123e4567-e89b-12d3-a456-42661417zzzz", deeplink.ErrInvalidReference},
		{"wrong scheme", "http://areas/123e4567-e89b-12d3-a456-426614174000", deeplink.ErrInvalidReference},
		{"invalid resource", "lunatask://habits/123e4567-e89b-12d3-a456-426614174000", deeplink.ErrUnsupportedResource},
		{"missing path", "lunatask://", deeplink.ErrInvalidReference},
		{"extra path", "lunatask://areas/foo/bar", deeplink.ErrInvalidReference},
	}

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

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

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

	const uuid = "3bbf1923-64ae-4bcf-96a9-9bb86c799dab"

	tests := []struct {
		name     string
		resource deeplink.Resource
		id       string
		want     string
	}{
		{"area", deeplink.Area, uuid, "lunatask://areas/" + uuid},
		{"goal", deeplink.Goal, uuid, "lunatask://goals/" + uuid},
		{"task", deeplink.Task, uuid, "lunatask://tasks/" + uuid},
		{"note", deeplink.Note, uuid, "lunatask://notes/" + uuid},
		{"person", deeplink.Person, uuid, "lunatask://people/" + uuid},
		{"notebook", deeplink.Notebook, uuid, "lunatask://notebooks/" + uuid},
	}

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

			got, err := deeplink.Build(testCase.resource, testCase.id)
			if err != nil {
				t.Errorf("Build(%v, %q) error = %v, want nil",
					testCase.resource, testCase.id, err)
			}

			if got != testCase.want {
				t.Errorf("Build(%v, %q) = %q, want %q",
					testCase.resource, testCase.id, got, testCase.want)
			}
		})
	}
}

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

	_, err := deeplink.Build(deeplink.Area, "not-a-uuid")
	if !errors.Is(err, deeplink.ErrInvalidReference) {
		t.Errorf("Build(Area, \"not-a-uuid\") error = %v, want %v", err, deeplink.ErrInvalidReference)
	}
}
